home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Source Code / Visual Basic Source Code.iso / vbsource / vbdatabs / winmain.cpp < prev    next >
C/C++ Source or Header  |  1999-03-17  |  122KB  |  3,972 lines

  1. // ------------------------------- //
  2. // -------- Start of File -------- //
  3. // ------------------------------- //
  4. // ----------------------------------------------------------- // 
  5. // C++ Source Code File Name: winmain.cpp 
  6. // Compiler Used: MSVC40, HPUX CPP 10.24
  7. // Produced By: Doug Gaer  
  8. // File Creation Date: 09/18/1997  
  9. // Date Last Modified: 03/18/1999
  10. // Copyright (c) 1997 Douglas M. Gaer
  11. // ----------------------------------------------------------- // 
  12. // ------------- Program Description and Details ------------- // 
  13. // ----------------------------------------------------------- // 
  14. /*
  15. The VBD C++ classes are copyright (c) 1997, by Douglas M. Gaer.
  16. All those who put this code or its derivatives in a commercial
  17. product MUST mention this copyright in their documentation for
  18. users of the products in which this code or its derivative
  19. classes are used. Otherwise, you have the freedom to redistribute
  20. verbatim copies of this source code, adapt it to your specific
  21. needs, or improve the code and release your improvements to the
  22. public provided that the modified files carry prominent notices
  23. stating that you changed the files and the date of any change.
  24.  
  25. THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND.
  26. THE ENTIRE RISK OF THE QUALITY AND PERFORMANCE OF THIS SOFTWARE
  27. IS WITH YOU. SHOULD ANY ELEMENT OF THIS SOFTWARE PROVE DEFECTIVE,
  28. YOU WILL ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR, OR
  29. CORRECTION.
  30.  
  31. This is a test program used to test the (P)ersistent base class
  32. in a practical database application using the wxWindow GUI library
  33. version 1.68
  34. */
  35. // ----------------------------------------------------------- // 
  36. #include <stdlib.h> // Needed for getenv under HPUX CPP
  37. #include "timer.h"
  38. #include "dbconfig.h"
  39. #include "winmain.h"
  40. #include "strutil.h"
  41. #include "asprint.h"
  42. #include "vbdstats.h"
  43. #include "btwalker.h"
  44.  
  45. // This struct was added to read Variable Block Headers because
  46. // the Status member of VBHeader struct in the vbdfile.h file
  47. // caused a syntax error when compiling this program under HPUX
  48. // CPP version 1024. 
  49. struct VBlockHeader // (V)ariable (B)lock (H)eader 
  50. {
  51.   UINT32 CkWord;      // (C)heck (W)ord for file integrity checks (4 bytes)
  52.   UINT32 Length;      // Length of this block including VB header (4 bytes) 
  53.   UINT32 VBStatus;    // Status of dynamic data stored in VB (4 byte)
  54.   FAU NextDeletedVB;  // Pointer to next deleted VB (4 bytes) 
  55. };
  56.  
  57. // (V)ariable (B)lock (D)atabse components
  58. static POD *DB;             // Global database pointer
  59. Grocery *agrocery = 0;      // Global data buffer used to add objects
  60. Grocery *cgrocery = 0;      // Global data buffer used to change objects
  61. Grocery *dgrocery = 0;      // Global data buffer used to display objects
  62. const char *WildCard = "*"; // Used for wild card searches 
  63.  
  64. // Define global field names for controls, displays, printing
  65. const char *KeyName = "ITEM NAME";
  66. const char *M2Name =  "BRAND NAME";
  67. const char *M3Name =  "STORE NAME";
  68. const char *M4Name =  "PRICE";
  69. const char *M5Name =  "QUANTITY";
  70. const char *M6Name =  "PURCHASING";
  71. const char *M7Name =  "LINE TOTAL";
  72. const char *M8Name =  "GRAND TOTAL";
  73. double grand_total = 0;
  74. double sales_tax = 0;
  75.  
  76. // Set buffer length for formatting strings
  77. const int sbuffer_len = 255;
  78.  
  79. // Output limit per string for ASCII printing
  80. const int StringOffset = 15;   // String limits
  81. const int PrintColsSpec = 111; // Columns limits
  82.  
  83. // Global mode indicators used to select items to be purchased
  84. int display_all = 0;  // Display items for purchase only
  85. int print_all = 0;    // Print items for purchase only
  86. int ps_print_all = 0; // PostScript print items for purchase only
  87. int as_print_all = 0; // ASCII print items for purchase only
  88. int view_all = 0;     // View total cost of items for purchase only
  89. int purchase_all = 1; // Used to set purchasing status
  90.  
  91. // Declare frame, subframe and menu objects
  92. MyFrame *frame = 0;
  93. wxMenuBar *menu_bar = 0;
  94. wxFrame *APanelFrame = 0;
  95. wxFrame *CPanelFrame = 0;
  96. wxFrame *DPanelFrame = 0;
  97.  
  98. #ifdef __USE_MSW_PRINTING__
  99. wxDialogBox *wxPageDialog = 0;  // MSW page setup dialog box
  100. MSWPrintingParameters MSWPrnPars;
  101. MSWPrintingParameters *MSWPrintSetup = &MSWPrnPars;
  102. const int mswpDocNameLen = 255;
  103. char mswpDocumentName[mswpDocNameLen];
  104. #endif // __USE_MSW_PRINTING__
  105.  
  106. // Variable used to print display list objects
  107. int print_list = 0;
  108. int num_objects = 0;
  109. int displaying_list = 0;
  110.  
  111. // Font, Pen, and Cursor objects
  112. wxFont *labelFont = 0;
  113. wxFont *itemFont = 0;
  114. wxFont *textWindowFont = 0;
  115.  
  116. // wxWindows control objects
  117. wxButton *btn_add_add = 0;          // Object Add Panel Add button
  118. wxButton *btn_add_can = 0;          // Object Add Panel Cancel button
  119. wxButton *btn_add_close = 0;        // Object Add Panel Close button
  120. wxButton *btn_add_revert = 0;       // Object Add Panel Revert button 
  121. wxChoice *add_PurchasingChoice = 0; // Add panel purchasing choice box
  122. char *PurchasingChoiceStrings[2] = {
  123.   "No",
  124.   "Yes"
  125. };
  126.  
  127. wxButton *btn_ch_sh = 0;           // Objedct Change Panel Search button
  128. wxButton *btn_ch_cm = 0;           // Object Change Panel Commit button
  129. wxButton *btn_ch_can = 0;          // Object Change Panel Cancel button
  130. wxButton *btn_ch_close = 0;        // Object Change Panel Close button
  131. wxButton *btn_ch_revert = 0;       // Object Change Panel Revert button 
  132. wxChoice *ch_PurchasingChoice = 0; // Change panel purchasing choice box
  133.  
  134. wxButton *btn_ds_nx = 0;     // Object Display Panel Next button
  135. wxButton *btn_ds_prev = 0;   // Object Display Panel Previous button
  136. wxButton *btn_ds_ch = 0;     // Object Display Panel Change button
  137. wxButton *btn_ds_rm = 0;     // Object Display Panel Remove button
  138. wxButton *btn_ds_close = 0;  // Object Display Panel Close button
  139.  
  140. #ifdef __USE_MSW_PRINTING__
  141. wxButton *btn_pdb_close = 0;     // MSW page setup dialog Close button
  142. wxButton *btn_pdb_cancel = 0;    // MSW page setup dialog Accept button
  143. wxButton *btn_pdb_accept = 0;    // MSW page setup dialog Accept button
  144. wxButton *btn_pdb_default = 0;   // MSW page setup dialog Default button
  145. wxSlider *LppSlider = 0;         // Lines per page slider
  146. wxSlider *CellSlider = 0;        // Cell width slider
  147. wxSlider *FsSlider = 0;          // Font size slider
  148. wxSlider *LRMSlider = 0;         // Left and right margin slider
  149. wxChoice *OrientationChoice = 0; // Orientation choice box
  150. char *OrChoiceStrings[2] = {
  151.   "Landscape",
  152.   "Portrait"
  153. };
  154.  
  155. wxChoice *FontChoice = 0;        // Font family choice box
  156. char *FontChoiceStrings[6] = {
  157.   "Swiss",      // wxSWISS
  158.   "Roman",      // wxROMAN
  159.   "Decorative", // wxDECORATIVE
  160.   "Modern",     // wxMODERN 
  161.   "Script",     // wxSCRIPT
  162.   "System"      // wxDEFAULT
  163. };
  164. #endif // __USE_MSW_PRINTING__
  165.  
  166. // This statement initializes the whole application and calls OnInit
  167. MyApp myApp;
  168.  
  169. // A macro needed for some compilers (AIX) that need 'main' to be defined
  170. // in the application itself.
  171. IMPLEMENT_WXWIN_MAIN
  172.  
  173. // `Main program' equivalent, creating windows and returning main app frame
  174. wxFrame *MyApp::OnInit(void)
  175. {
  176.   // Create the main frame window
  177.   frame = new MyFrame(NULL, (char *)ProgramName, 50, 50, 400, 300);
  178.  
  179.   // Give this frame a status line
  180.   frame->CreateStatusLine(1);
  181.   
  182.   // Give it an icon
  183. #ifdef wx_msw
  184.   frame->SetIcon(new wxIcon("vbdbase"));
  185. #endif
  186. #ifdef wx_x
  187.   frame->SetIcon(new wxIcon("vbdbase.xbm"));
  188. #endif
  189.  
  190.   // File menu 
  191.   wxMenu *file_menu = new wxMenu;
  192.   file_menu->Append(FILE_VBDSTATS, "VBD file &Stats", 
  193.             "Display VBD file statistics");
  194.   file_menu->AppendSeparator();
  195.   file_menu->Append(FILE_EXPORT, "Export","Export database to ASCII file");
  196.   file_menu->Append(FILE_IMPORT, "Import", "Import ASCII file into database");
  197.   file_menu->Append(FILE_TEMPLATE, "Create Template",
  198.             "Create an ASCII template for import file");
  199.   file_menu->AppendSeparator();
  200.   file_menu->Append(FILE_BACKUP, "Backup",
  201.             "Backup the database to another file");
  202.   file_menu->Append(FILE_MERGE, "Merge",
  203.             "Merge the contents of another database file");
  204.   file_menu->AppendSeparator();
  205.   file_menu->Append(FILE_COMPARE_INDEX, "Compare Index File",
  206.             "Compare the index file to the database file");
  207.   file_menu->Append(FILE_REBUILD_INDEX, "Rebuild Index File",
  208.             "Rebuild the index file for this database");
  209.   file_menu->AppendSeparator();
  210.   file_menu->Append(FILE_QUIT, "E&xit","Exit this program");
  211.  
  212.   // Edit menu
  213.   wxMenu *edit_menu = new wxMenu;
  214.   edit_menu->Append(EDIT_CUT, "Cut\tCtrl+X", "Cut text and copy to clipboard");
  215.   edit_menu->AppendSeparator();
  216.   edit_menu->Append(EDIT_COPY, "Copy\tCtrl+C", "Copy text to clipboard");
  217.   edit_menu->AppendSeparator();
  218.   edit_menu->Append(EDIT_PASTE, "Paste\tCtrl+V", "Paste text from clipboard");
  219.   
  220.   // Database menu
  221.   wxMenu *db_menu = new wxMenu;
  222.   db_menu->Append(DB_DISPLAY_PURCHASING,
  223.           "&Display Objects to be Purchased",
  224.           "Display only objects selected for purchase ");
  225.   db_menu->AppendSeparator();
  226.   db_menu->Append(DB_DISPLAY_ALL, "Display All Objects",
  227.           "Display all objects in the database");
  228.   db_menu->AppendSeparator();
  229.   db_menu->Append(DB_ADD, "&Add", "Add objects to the database");
  230.   db_menu->AppendSeparator();
  231.   db_menu->Append(DB_CHANGE, "&Change", "Change an object in the database");
  232.   db_menu->AppendSeparator();
  233.   db_menu->Append(DB_REMOVE, "&Remove", "Remove an object from the database");
  234.   db_menu->AppendSeparator();
  235.   db_menu->Append(DB_RESET_PURCHASING, "Reset Purchasing List",
  236.           "Setting all objects for purchase to no");
  237.   db_menu->AppendSeparator();
  238.   db_menu->Append(DB_SET_ALL_PURCHASING, "Set All For Purchase",
  239.           "Purchase all the objects in the database");
  240.   
  241.   // Find menu
  242.   wxMenu *find_menu = new wxMenu;
  243.   const char *Prompt = "Find by ";
  244.   UString s(Prompt); int PromptLen = strlen(Prompt); int StringLen = 0;
  245.  
  246.   s = s + KeyName; StringLen = strlen(KeyName);
  247.   find_menu->Append(FIND_BYNAME, s.c_str(), s.c_str());
  248.   s.DeleteAt(PromptLen, StringLen);
  249.   find_menu->AppendSeparator();
  250.   
  251.   s = s + M2Name; StringLen = strlen(M2Name);
  252.   find_menu->Append(FIND_BYBRAND, s.c_str(), s.c_str());
  253.   s.DeleteAt(PromptLen, StringLen);
  254.   find_menu->AppendSeparator();
  255.   
  256.   s = s + M3Name; StringLen = strlen(M3Name);
  257.   find_menu->Append(FIND_BYSTORE, s.c_str(), s.c_str());
  258.   s.DeleteAt(PromptLen, StringLen);
  259.  
  260.   // Print menu
  261.   wxMenu *print_menu = new wxMenu;
  262. #ifdef __USE_MSW_PRINTING__
  263.  
  264.   print_menu->Append(WXPRINT_PRINT_PURCHASING, "Print Objects to be Purchased",
  265.              "Print only the objects selected for purchase");
  266.   print_menu->Append(WXPRINT_PRINT_ALL, "Print All Objects",
  267.              "Print all objects to the selected printer");
  268.   print_menu->AppendSeparator();
  269.   print_menu->Append(WXPRINT_PRINTER_SETUP, "Printer Setup",
  270.              "Configure the seleted printer");
  271.   print_menu->Append(WXPRINT_PAGE_SETUP, "Page Setup",
  272.              "Set the page parameters before printing");
  273.   print_menu->AppendSeparator();
  274.   print_menu->Append(WXPRINT_PREVIEW_PURCHASING,
  275.              "Print Preview Objects for Purchase",
  276.              "Preview before printing objects for purchase");
  277.   print_menu->Append(WXPRINT_PREVIEW_ALL, "Print Preview for All Objects",
  278.              "Preview before printing all objects");
  279.   print_menu->AppendSeparator();
  280. #endif // __USE_MSW_PRINTING__
  281.  
  282.   print_menu->Append(PRINT_POSTSCRIPT_PURCHASING, "Print to PostScript file",
  283.              "Print objects for purchase to PostScript file");
  284.  
  285.   print_menu->Append(PRINT_POSTSCRIPT_ALL,
  286.              "Print all Objects to PostScript file",
  287.              "Print all objects to a PostScript file");
  288.   print_menu->AppendSeparator();
  289.   print_menu->Append(PRINT_ASCII_PURCHASING, "Print to Text File",
  290.              "Print objects for purchase to text file");
  291.   print_menu->Append(PRINT_ASCII_ALL, "Print all Objects to Text File",
  292.              "Print all objects to a text file");
  293.   
  294.   // View menu
  295.   wxMenu *view_menu = new wxMenu;
  296.   view_menu->Append(VIEW_CLEAR, "Clear Window", "Clear this text window");
  297.   view_menu->AppendSeparator();
  298.   view_menu->Append(VIEW_TOTAL_PURCHASING, "View Cost of Purchase",
  299.             "View total cost of objects selected for purchase");
  300.   view_menu->AppendSeparator();
  301.   view_menu->Append(VIEW_TOTAL_ALL, "View Cost All Objects",
  302.             "View total cost of all the objects");
  303.   // Help menu
  304.   wxMenu *help_menu = new wxMenu;
  305.   help_menu->Append(HELP_ABOUT, "&About", "Info about this program");
  306.   help_menu->AppendSeparator();
  307.   help_menu->Append(HELP_USERLEVEL, "Access Rights",
  308.             "Display your user access rights");
  309.   
  310.   // Make all the menu bars  
  311.   menu_bar = new wxMenuBar;
  312.   menu_bar->Append(file_menu, "&File");
  313.   menu_bar->Append(edit_menu, "&Edit");
  314.   menu_bar->Append(db_menu, "Data&base");
  315.   menu_bar->Append(find_menu, "F&ind");
  316.   menu_bar->Append(print_menu, "&Print");
  317.   menu_bar->Append(view_menu, "&View");
  318.   menu_bar->Append(help_menu, "&Help");
  319.   frame->SetMenuBar(menu_bar);
  320.  
  321.   // Associate the menu bar with the frame
  322.   frame->SetMenuBar(menu_bar);
  323.  
  324.   // Create a text window in the main frame
  325.   frame->textWin = new MyTextWindow(frame, 0, 250, 400, 250,
  326.                     wxNATIVE_IMPL);
  327.   frame->textWin->DragAcceptFiles(TRUE);
  328.   
  329. // *********************************************************** //
  330. // Object Add Panel Code Starts Here 
  331. // *********************************************************** //
  332.   frame->addText = new MyText; // Init MyText Class pointer
  333.   APanelFrame = new wxFrame(NULL, "Adding Object", 0, 0, 390, 390);
  334.  
  335.   // Panel fonts
  336.   labelFont = new wxFont(12, wxSWISS, wxNORMAL, wxBOLD);
  337.   itemFont = new wxFont(11, wxSWISS, wxNORMAL, wxBOLD);
  338.  
  339.   // Give it an icon
  340. #ifdef wx_msw
  341.   APanelFrame->SetIcon(new wxIcon("vbdbase"));
  342. #endif
  343. #ifdef wx_x
  344.   APanelFrame->SetIcon(new wxIcon("vbdbase.xbm"));
  345. #endif
  346.  
  347.   int apfwidth, apfheight;
  348.   APanelFrame->GetClientSize(&apfwidth, &apfheight);
  349.  
  350.   // Make a panel in the subframe
  351.   frame->apanel = new wxPanel(APanelFrame, 0, 0,
  352.                   apfwidth, apfheight); 
  353.   frame->apanel->SetLabelPosition(wxVERTICAL);
  354.   frame->apanel->SetLabelFont(labelFont);
  355.   frame->apanel->SetButtonFont(itemFont);
  356.   frame->apanel->SetFont(itemFont);
  357.  
  358.   // Needed to line up first addText box under motif 
  359.   frame->apanel->NewLine(); 
  360.  
  361.   frame->addText->item_name = new wxText(frame->apanel, NULL,
  362.                      (char *)KeyName, "",-1,-1,150,-1); 
  363.   frame->apanel->NewLine();
  364.   frame->addText->brand = new wxText(frame->apanel, (wxFunction)&text_proc,
  365.                      (char *)M2Name, "", -1, -1, 150, -1);
  366.   frame->apanel->NewLine();
  367.   frame->addText->store = new wxText(frame->apanel, (wxFunction)&text_proc,
  368.                      (char *)M3Name, "", -1, -1, 150, -1);
  369.   frame->apanel->NewLine();
  370.   frame->addText->price = new wxText(frame->apanel, (wxFunction)&text_proc,
  371.                      (char *)M4Name, "", -1, -1, 75, -1);
  372.   frame->apanel->NewLine();
  373.   frame->addText->quantity = new wxText(frame->apanel, (wxFunction)&text_proc,
  374.                     (char *)M5Name, "", -1, -1, 75, -1); 
  375.   frame->apanel->NewLine();
  376.   add_PurchasingChoice = new wxChoice(frame->apanel, NULL, (char *)M6Name,
  377.                       -1, -1, -1, -1, 2,
  378.                       PurchasingChoiceStrings);
  379.   add_PurchasingChoice->SetSelection(0);
  380.  
  381.   frame->apanel->NewLine();
  382.   frame->apanel->NewLine();
  383.   
  384.   btn_add_add = new wxButton(frame->apanel, (wxFunction)&AddBtnProc, "Add");
  385.   btn_add_add->SetClientData((char*)ADD_BUTTON_ADD); // ID the button  
  386.  
  387.   btn_add_can = new wxButton(frame->apanel,(wxFunction)&AddBtnProc, "Cancel");
  388.   btn_add_can->SetClientData((char*)ADD_BUTTON_CANCEL); // ID the button  
  389.  
  390.   btn_add_close = new wxButton(frame->apanel, (wxFunction)&AddBtnProc,
  391.                    "Close");
  392.   btn_add_close->SetClientData((char*)ADD_BUTTON_CLOSE); // ID the button  
  393.  
  394.   btn_add_revert = new wxButton(frame->apanel, (wxFunction)&AddBtnProc,
  395.                 "Revert");
  396.   btn_add_revert->SetClientData((char*)ADD_BUTTON_REVERT); // ID the button  
  397. // *********************************************************** //
  398. // Object Add Panel Code Ends Here 
  399. // *********************************************************** //
  400.  
  401. // *********************************************************** //
  402. // Object Change Panel Code Starts Here 
  403. // *********************************************************** //
  404.   frame->changeText = new MyText; // Init MyText Class pointer
  405.   CPanelFrame = new wxFrame(NULL, "Changing Object", 0, 0, 400, 400);
  406.  
  407.   // Give it an icon
  408. #ifdef wx_msw
  409.   CPanelFrame->SetIcon(new wxIcon("vbdbase"));
  410. #endif
  411. #ifdef wx_x
  412.   CPanelFrame->SetIcon(new wxIcon("vbdbase.xbm"));
  413. #endif
  414.  
  415.   int cpfwidth, cpfheight;
  416.   CPanelFrame->GetClientSize(&cpfwidth, &cpfheight);
  417.  
  418.   // Make a panel in the subframe
  419.   frame->cpanel = new wxPanel(CPanelFrame, 0, 0,
  420.                   cpfwidth, cpfheight);
  421.   frame->cpanel->SetLabelPosition(wxVERTICAL);
  422.   frame->cpanel->SetLabelFont(labelFont);
  423.   frame->cpanel->SetButtonFont(itemFont);
  424.   frame->cpanel->SetFont(itemFont);
  425.  
  426.   // Needed to line up first panel with the others under motif 
  427.   frame->cpanel->NewLine(); 
  428.  
  429.   UString cmesg("Enter the ");
  430.   cmesg = cmesg + KeyName + " and click on Search.";
  431.   wxMessage *message = new wxMessage(frame->cpanel, cmesg.c_str());
  432.   frame->cpanel->NewLine();
  433.   
  434.   frame->changeText->item_name = new wxText(frame->cpanel, NULL,
  435.                         (char *)KeyName, "",-1,-1,150,-1); 
  436.   frame->cpanel->NewLine();
  437.   frame->changeText->brand = new wxText(frame->cpanel, (wxFunction)&text_proc,
  438.                     (char *)M2Name, "", -1, -1, 150, -1);
  439.   frame->cpanel->NewLine();
  440.   frame->changeText->store = new wxText(frame->cpanel, (wxFunction)&text_proc,
  441.                     (char *)M3Name, "", -1, -1, 150, -1);
  442.   frame->cpanel->NewLine();
  443.   frame->changeText->price = new wxText(frame->cpanel, (wxFunction)&text_proc,
  444.                     (char *)M4Name, "", -1, -1, 75, -1);
  445.   frame->changeText->quantity = new wxText(frame->cpanel,
  446.                        (wxFunction)&text_proc,
  447.                        (char *)M5Name, "",
  448.                        -1, -1, 75, -1); 
  449.   frame->cpanel->NewLine();
  450.   ch_PurchasingChoice = new wxChoice(frame->cpanel, NULL, (char *)M6Name,
  451.                      -1, -1, -1, -1, 2,
  452.                      PurchasingChoiceStrings);
  453.   ch_PurchasingChoice->SetSelection(0);
  454.  
  455.   frame->cpanel->NewLine();
  456.   frame->changeText->line_total = new wxText(frame->cpanel,
  457.                          (wxFunction)&text_proc,
  458.                          (char *)M7Name, "",
  459.                          -1, -1, 150, -1);
  460.   frame->changeText->line_total->SetEditable(FALSE);
  461.   frame->cpanel->NewLine();
  462.   frame->cpanel->NewLine();
  463.   btn_ch_sh = new wxButton(frame->cpanel, (wxFunction)&ChBtnProc, "Search");
  464.   btn_ch_sh->SetClientData((char*)CHANGE_BUTTON_SH); // ID the button  
  465.  
  466.   btn_ch_cm = new wxButton(frame->cpanel, (wxFunction)&ChBtnProc, "Commit");
  467.   btn_ch_cm->SetClientData((char*)CHANGE_BUTTON_CM); // ID the button  
  468.   btn_ch_cm->Enable(0);
  469.   
  470.   btn_ch_can = new wxButton(frame->cpanel,(wxFunction)&ChBtnProc, "Cancel");
  471.   btn_ch_can->SetClientData((char*)CHANGE_BUTTON_CANCEL); // ID the button  
  472.  
  473.   btn_ch_close = new wxButton(frame->cpanel, (wxFunction)&ChBtnProc, "Close");
  474.   btn_ch_close->SetClientData((char*)CHANGE_BUTTON_CLOSE); // ID the button  
  475.  
  476.   btn_ch_revert = new wxButton(frame->cpanel, (wxFunction)&ChBtnProc,
  477.                 "Revert");
  478.   btn_ch_revert->SetClientData((char*)CHANGE_BUTTON_REVERT); // ID the button  
  479. // *********************************************************** //
  480. // Object Change Panel Code Ends Here 
  481. // *********************************************************** //
  482.  
  483. // *********************************************************** //
  484. // Object Display Panel Code Starts Here 
  485. // *********************************************************** //
  486.   frame->displayText = new MyText; // Init MyText Class pointer
  487.   DPanelFrame = new wxFrame(NULL, "Displaying Objects", 0, 0,
  488.                 400, 400);
  489.  
  490.   // Give it an icon
  491. #ifdef wx_msw
  492.   DPanelFrame->SetIcon(new wxIcon("vbdbase"));
  493. #endif
  494. #ifdef wx_x
  495.   DPanelFrame->SetIcon(new wxIcon("vbdbase.xbm"));
  496. #endif
  497.  
  498.   int dpfwidth, dpfheight;
  499.   DPanelFrame->GetClientSize(&dpfwidth, &dpfheight);
  500.  
  501.   // Make a panel in the subframe
  502.   frame->dpanel = new wxPanel(DPanelFrame, 0, 0,
  503.                   dpfwidth, dpfheight);
  504.   frame->dpanel->SetLabelPosition(wxVERTICAL);
  505.   frame->dpanel->SetLabelFont(labelFont);
  506.   frame->dpanel->SetButtonFont(itemFont);
  507.   frame->dpanel->SetFont(itemFont);
  508.  
  509.   // Needed to line up first addText box under motif 
  510.   frame->dpanel->NewLine(); 
  511.  
  512.   frame->displayText->item_name = new wxText(frame->dpanel, NULL,
  513.                          (char *)KeyName, "",-1,-1,150,-1);
  514.   frame->displayText->item_name->SetEditable(FALSE);
  515.  
  516.   frame->dpanel->NewLine();
  517.   frame->displayText->brand = new wxText(frame->dpanel, (wxFunction)&text_proc,
  518.                      (char *)M2Name, "", -1, -1, 150, -1);
  519.   frame->displayText->brand->SetEditable(FALSE);
  520.  
  521.   frame->dpanel->NewLine();
  522.   frame->displayText->store = new wxText(frame->dpanel, (wxFunction)&text_proc,
  523.                      (char *)M3Name, "", -1, -1, 150, -1);
  524.   frame->displayText->store->SetEditable(FALSE);
  525.  
  526.   frame->dpanel->NewLine();
  527.   frame->displayText->price = new wxText(frame->dpanel, (wxFunction)&text_proc,
  528.                      (char *)M4Name, "", -1, -1, 75, -1);
  529.   frame->displayText->price->SetEditable(FALSE);
  530.  
  531.   frame->displayText->quantity = new wxText(frame->dpanel,
  532.                         (wxFunction)&text_proc,
  533.                         (char *)M5Name, "",
  534.                         -1, -1, 75, -1);
  535.   frame->displayText->quantity->SetEditable(FALSE);
  536.   
  537.   frame->dpanel->NewLine();
  538.   frame->displayText->purchasing = new wxText(frame->dpanel,
  539.                          (wxFunction)&text_proc,
  540.                          (char *)M6Name, "",
  541.                          -1, -1, 75, -1);
  542.   frame->displayText->purchasing->SetEditable(FALSE);
  543.  
  544.   frame->dpanel->NewLine();
  545.   frame->displayText->line_total = new wxText(frame->dpanel,
  546.                           (wxFunction)&text_proc,
  547.                           (char *)M7Name, "",
  548.                           -1, -1, 75, -1);
  549.   frame->displayText->line_total->SetEditable(FALSE);
  550.  
  551.   frame->dpanel->NewLine();
  552.   frame->dpanel->NewLine();
  553.   btn_ds_nx = new wxButton(frame->dpanel, (wxFunction)&DsBtnProc, "Next");
  554.   btn_ds_nx->SetClientData((char*)DISPLAY_BUTTON_NX); // ID the button  
  555.   
  556.   btn_ds_prev = new wxButton(frame->dpanel, (wxFunction)&DsBtnProc, "Prior");
  557.   btn_ds_prev->SetClientData((char*)DISPLAY_BUTTON_PREV); // ID the button  
  558.  
  559.   btn_ds_ch = new wxButton(frame->dpanel,(wxFunction)&DsBtnProc, "Change");
  560.   btn_ds_ch->SetClientData((char*)DISPLAY_BUTTON_CHANGE); // ID the button  
  561.  
  562.   btn_ds_close = new wxButton(frame->dpanel, (wxFunction)&DsBtnProc, "Close");
  563.   btn_ds_close->SetClientData((char*)DISPLAY_BUTTON_CLOSE); // ID the button  
  564.  
  565.   btn_ds_rm = new wxButton(frame->dpanel, (wxFunction)&DsBtnProc, "Remove");
  566.   btn_ds_rm->SetClientData((char*)DISPLAY_BUTTON_REMOVE); // ID the button
  567. // *********************************************************** //
  568. // Object Display Panel Code Ends Here 
  569. // *********************************************************** //
  570.  
  571.   // Show the frames
  572.   frame->Show(TRUE);
  573.   APanelFrame->Show(FALSE);
  574.   CPanelFrame->Show(FALSE);
  575.   displaying_list = 0;
  576.   DPanelFrame->Show(FALSE);
  577.   
  578.   // Vaiable Block Database components
  579.   char *FileName = 0;
  580.   char *CurrentCfgFile = 0;
  581.   char *CfgFile = 0;
  582.   Config *CfgData = new Config;
  583.   char *AdminUser = 0;
  584.   double dfp_val = 0;
  585.  
  586.   const char *DefaultWelcomeMesg = "welcome.txt";
  587.   char *WelcomeMesgFile = 0;
  588.  
  589. #ifdef __USE_MSW_PRINTING__
  590.   // Default values for wxWindows MSW Printing
  591.   int mswp_lines_per_page = 0;
  592.   int mswp_cell_length = 0;
  593.   int mswp_font_size = 0;
  594.   int mswp_left_margin = 0;
  595.   char *mswp_orientation = 0;
  596.   char *mswp_doc_name = 0;
  597.   char *mswp_font = 0;
  598. #endif // __USE_MSW_PRINTING__
  599.   
  600.   // Look for CfgFile name in environment
  601.   if((CurrentCfgFile = getenv(EnvSetting)) == 0)
  602.      CfgFile = (char *)DefaultCfgFile;
  603.   else
  604.     CfgFile = CurrentCfgFile;
  605.  
  606.   // Use default file name if no file is specifed on command line
  607.   if(argc < 2) {
  608.     int FileStatus = CfgData->Load((char *)CfgFile);
  609.     if(!FileStatus) {
  610.       Error->Message("Cannot locate any database files!\n",
  611.              "Defaulting to: ", DefaultDBFileName);
  612.       FileName = (char *)DefaultDBFileName;
  613.       WelcomeMesgFile = (char *)DefaultWelcomeMesg;
  614.     }
  615.     else { 
  616. // *********************************************************** //
  617. // Add all startup config file entries here
  618. // *********************************************************** //
  619.       FileName = CfgData->GetStrValue("DBFileName");
  620.       AdminUser = CfgData->GetStrValue("AdminUser");
  621.       WelcomeMesgFile = CfgData->GetStrValue("WelcomeMessageFile");
  622.       sales_tax = CfgData->GetDFPValue("SalesTax");
  623. #ifdef __USE_MSW_PRINTING__
  624.   // Default values for wxWindows MSW Printing
  625.   mswp_lines_per_page = CfgData->GetIntValue("mswpLinesPerPage");
  626.   mswp_cell_length = CfgData->GetIntValue("mswpCellLength");
  627.   mswp_font_size = CfgData->GetIntValue("mswpFontSize");
  628.   mswp_left_margin = CfgData->GetIntValue("mswpLeftMargin");
  629.   mswp_orientation = CfgData->GetStrValue("mswpOrientation");
  630.   mswp_font = CfgData->GetStrValue("mswpFont");
  631.   mswp_doc_name = CfgData->GetStrValue("mswpDocumentName");
  632. #endif // __USE_MSW_PRINTING__
  633. // *********************************************************** //
  634.  
  635.       if(!FileName) {
  636.         UString comp("\nDefaulting to: ");
  637.     comp = comp + DefaultDBFileName;
  638.     Error->Message("DBFileName section missing in config file:\n",
  639.                CfgFile, comp.c_str());
  640.     FileName = (char *)DefaultDBFileName;
  641.       }
  642.     }
  643.   }
  644.   else {
  645.     FileName = argv[1];
  646.   }
  647.  
  648.   if(!AdminUser) {
  649.     AdminRights = 0;
  650.     frame->SetStatusText((char *)ProgramName);
  651.   }
  652.   else {
  653.     int result = strcmp(AdminUser, "TRUE");
  654.     if(result == 0) {
  655.       AdminRights = 1;
  656.       frame->SetStatusText("ADMIN USER");
  657.     }
  658.     else {
  659.       AdminRights = 0;
  660.       frame->SetStatusText((char *)ProgramName);
  661.     }
  662.   }
  663.  
  664.   if(!WelcomeMesgFile) 
  665.       WelcomeMesgFile = (char *)DefaultWelcomeMesg;
  666.  
  667. #ifdef __USE_MSW_PRINTING__
  668.   // Default values for wxWindows MSW Printing
  669.   if(mswp_lines_per_page > 0) {
  670.     MSWPrintSetup->lines_per_page = mswp_lines_per_page;
  671.     MSWPrintSetup->prev_lines_per_page = mswp_lines_per_page;
  672.     MSWPrintSetup->default_lines_per_page = mswp_lines_per_page;
  673.   }
  674.  
  675.   if(mswp_cell_length > 0) {
  676.     MSWPrintSetup->cell_length = mswp_cell_length;
  677.     MSWPrintSetup->prev_cell_length = mswp_cell_length;
  678.     MSWPrintSetup->default_cell_length = mswp_cell_length;
  679.   }
  680.  
  681.   if(mswp_font_size > 0) {
  682.     MSWPrintSetup->font_size = mswp_font_size;
  683.     MSWPrintSetup->prev_font_size = mswp_font_size;
  684.     MSWPrintSetup->default_font_size = mswp_font_size;
  685.   }
  686.  
  687.   if(mswp_left_margin > 0) {
  688.     MSWPrintSetup->lr_margin = mswp_left_margin;
  689.     MSWPrintSetup->prev_lr_margin = mswp_left_margin;
  690.     MSWPrintSetup->default_lr_margin = mswp_left_margin;
  691.   }
  692.  
  693.   if(mswp_orientation != 0) {
  694.     if(strcmp(mswp_orientation, "PORTRAIT") == 0) {
  695.       MSWPrintSetup->orientation = 1;
  696.       MSWPrintSetup->prev_orientation = 1;
  697.       MSWPrintSetup->default_orientation = 1;
  698.     }
  699.     if(strcmp(mswp_orientation, "LANDSCAPE") == 0) {
  700.       MSWPrintSetup->orientation = 0;
  701.       MSWPrintSetup->prev_orientation = 0;
  702.       MSWPrintSetup->default_orientation = 0;
  703.     }
  704.   }
  705.   
  706.   if(mswp_font != 0) {
  707.     if(strcmp(mswp_font, "SWISS") == 0) {
  708.       MSWPrintSetup->font = 0;
  709.       MSWPrintSetup->prev_font = 0;
  710.       MSWPrintSetup->default_font = 0;
  711.     }
  712.     if(strcmp(mswp_font, "ROMAN") == 0) {
  713.       MSWPrintSetup->font = 1;
  714.       MSWPrintSetup->prev_font = 1;
  715.       MSWPrintSetup->default_font = 1;
  716.     }
  717.     if(strcmp(mswp_font, "DECORATIVE") == 0) {
  718.       MSWPrintSetup->font = 2;
  719.       MSWPrintSetup->prev_font = 2;
  720.       MSWPrintSetup->default_font = 2;
  721.     }
  722.     if(strcmp(mswp_font, "MODERN") == 0) {
  723.       MSWPrintSetup->font = 3;
  724.       MSWPrintSetup->prev_font = 3;
  725.       MSWPrintSetup->default_font = 3;
  726.     }
  727.     if(strcmp(mswp_font, "SCRIPT") == 0) {
  728.       MSWPrintSetup->font = 4;
  729.       MSWPrintSetup->prev_font = 4;
  730.       MSWPrintSetup->default_font = 4;
  731.     }
  732.     if(strcmp(mswp_font, "SYSTEM") == 0) {
  733.       MSWPrintSetup->font = 5;
  734.       MSWPrintSetup->prev_font = 5;
  735.       MSWPrintSetup->default_font = 5;
  736.     }
  737.   }
  738.  
  739.   for(int i = 0; i < mswpDocNameLen; i++) mswpDocumentName[i] = 0;
  740.   if(mswp_doc_name != 0) 
  741.     strcpy(mswpDocumentName, mswp_doc_name);
  742.   else
  743.     strcpy(mswpDocumentName, ProgramName);
  744. #endif // __USE_MSW_PRINTING__
  745.  
  746.   CfgData->UnLoad(); // Unload the Config file from memory
  747.  
  748.   // Initialize global database pointer
  749.   // NOTE: Index file and data file will share the same file name
  750.   // with different file extensions. The data file will have a 
  751.   // .pod extension and the index file will have a .btx extension.
  752.   if(AdminRights == 1)
  753.     DB = new POD(FileName, RWMode, 1, CacheSize);
  754.   else
  755.     DB = new POD(FileName, ROMode, 1, CacheSize);
  756.   
  757.   agrocery = new Grocery(DB); // Initialize global buffer pointer
  758.   cgrocery = new Grocery(DB); // Initialize global buffer pointer
  759.   dgrocery = new Grocery(DB); // Initialize global buffer pointer
  760.   
  761.   // Display the welcome message if it exists
  762.   frame->textWin->LoadFile(WelcomeMesgFile);
  763.  
  764.   // Return the main frame window
  765.   return frame;
  766. }
  767.  
  768. MyFrame::MyFrame(wxFrame *frame, char *title, int x, int y, int w, int h):
  769.   wxFrame(frame, title, x, y, w, h)
  770. {
  771.   textWin = 0;
  772.   apanel = 0;
  773.   cpanel = 0;
  774.   dpanel = 0;
  775.   addText = 0;
  776.   changeText = 0;
  777. }
  778.  
  779. Bool MyFrame::OnClose(void)
  780. // Define the behaviour for the frame closing
  781. {
  782.   // Close sub-frames
  783.   if(APanelFrame) {
  784.     APanelFrame->Close(TRUE);
  785.     delete APanelFrame;
  786.   }
  787.   
  788.   if(CPanelFrame) {
  789.     CPanelFrame->Close(TRUE);
  790.     delete CPanelFrame;
  791.   }
  792.   
  793.   if(DPanelFrame) {
  794.     DPanelFrame->Close(TRUE);
  795.     delete DPanelFrame;
  796.   }
  797.   
  798.   // Close main frame
  799.   Show(FALSE);
  800.  
  801.   // Clean up Variable Block Database objects
  802.   if(DB) delete DB;
  803.   if(agrocery) delete agrocery;
  804.   if(cgrocery) delete cgrocery;
  805.   if(dgrocery) delete dgrocery;
  806.   return TRUE;
  807. }
  808.  
  809. void MyFrame::OnMenuCommand(int id)
  810. // Intercept menu commands
  811. {
  812.   switch (id) {
  813.     case FILE_QUIT:
  814.       if (OnClose()) delete this;
  815.       break;
  816.  
  817.     case FILE_VBDSTATS:
  818.       textWin->Clear();
  819.       *(textWin) << "----- Database file statistics -----" << "\n";
  820.       VBDStats(textWin, DB->OpenDatabase());
  821.       *(textWin) << "----- Index file statistics -----" << "\n";
  822.       VBDStats(textWin, DB->OpenIndexFile());
  823.       break;
  824.  
  825.     case FILE_EXPORT:
  826.       ExportToASCII(*textWin);
  827.       break;
  828.  
  829.     case FILE_IMPORT:
  830.       ImportFromASCII(*textWin);
  831.       break;
  832.  
  833.     case FILE_BACKUP:
  834.       BackUp(*textWin);
  835.       break;
  836.  
  837.     case FILE_MERGE:
  838.       Merge(*textWin);
  839.       break;
  840.  
  841.     case FILE_TEMPLATE:
  842.       CreateTemplate(*textWin);
  843.       break;
  844.  
  845.     case FILE_COMPARE_INDEX:
  846.       CompareIndexFile(*textWin);
  847.       break;
  848.       
  849.     case FILE_REBUILD_INDEX:
  850.       RebuildIndexFile(*textWin);
  851.       break;
  852.  
  853.     case EDIT_CUT:
  854.       textWin->Cut();
  855.       break;
  856.  
  857.     case EDIT_COPY:
  858.       textWin->Copy();
  859.       break;
  860.       
  861.     case EDIT_PASTE:
  862.       textWin->Paste();
  863.       break;
  864.  
  865.     case DB_ADD: 
  866.       Add(*textWin);
  867.       break;
  868.       
  869.     case DB_CHANGE:
  870.       Change(*textWin);
  871.       break;
  872.       
  873.     case DB_REMOVE:
  874.       Remove(*textWin);
  875.       break;
  876.  
  877.     case DB_DISPLAY_PURCHASING:
  878.       display_all = 0;
  879.       DisplayDB(*textWin);
  880.       break;
  881.  
  882.     case DB_DISPLAY_ALL:
  883.       display_all = 1;
  884.       DisplayDB(*textWin);
  885.       break;
  886.  
  887.     case DB_RESET_PURCHASING:
  888.       SetPurchasing(*textWin, 'N');
  889.       break;
  890.  
  891.     case DB_SET_ALL_PURCHASING:
  892.       SetPurchasing(*textWin, 'Y');
  893.       break;
  894.       
  895.     case FIND_BYNAME:
  896.       FindBy(*textWin, KeyName, NAME);
  897.       break;
  898.       
  899.     case FIND_BYBRAND:
  900.       FindBy(*textWin, M2Name, BRAND);
  901.       break;
  902.  
  903.     case FIND_BYSTORE:
  904.       FindBy(*textWin, M3Name, STORE);
  905.       break;
  906.  
  907. #ifdef __USE_MSW_PRINTING__
  908.     case WXPRINT_PRINT_PURCHASING:
  909.       {
  910.     print_all = 0;
  911. #ifdef wx_msw
  912.       myApp.SetPrintMode(wxPRINT_WINDOWS);
  913. #else 
  914.       // Allow MSW style printing under UNIX
  915.       myApp.SetPrintMode(wxPRINT_POSTSCRIPT);
  916. #endif
  917.     wxPrintData printData;
  918.  
  919.     if(MSWPrintSetup->orientation == 0) 
  920.       printData.SetOrientation(wxLANDSCAPE);
  921.     else
  922.       printData.SetOrientation(wxPORTRAIT);
  923.     
  924.     wxPrinter printer(&printData);
  925.     if(displaying_list) { 
  926.       int yn = wxMessageBox("Print display list objects?",
  927.                 "Program Message", wxYES_NO|wxCENTRE);
  928.       if(yn == wxYES) print_list = 1; else print_list = 0;
  929.     }
  930.     else
  931.       print_list = 0;
  932.  
  933.     wGrocPrint printout((char *)ProgramName);
  934.     if (!printer.Print(this, &printout, TRUE))
  935.       wxMessageBox("The document was not printed.",
  936.                "Printing", wxOK);
  937.     break;
  938.       }
  939.  
  940.     case WXPRINT_PRINT_ALL:
  941.       {
  942.     print_all = 1;
  943. #ifdef wx_msw
  944.       myApp.SetPrintMode(wxPRINT_WINDOWS);
  945. #else 
  946.       // Allow MSW style printing under UNIX
  947.       myApp.SetPrintMode(wxPRINT_POSTSCRIPT);
  948. #endif
  949.     wxPrintData printData;
  950.  
  951.     if(MSWPrintSetup->orientation == 0) 
  952.       printData.SetOrientation(wxLANDSCAPE);
  953.     else
  954.       printData.SetOrientation(wxPORTRAIT);
  955.     
  956.     wxPrinter printer(&printData);
  957.     if(displaying_list) { 
  958.       int yn = wxMessageBox("Print display list objects?",
  959.                 "Program Message", wxYES_NO|wxCENTRE);
  960.       if(yn == wxYES) print_list = 1; else print_list = 0;
  961.     }
  962.     else
  963.       print_list = 0;
  964.  
  965.     wGrocPrint printout((char *)ProgramName);
  966.     if (!printer.Print(this, &printout, TRUE))
  967.       wxMessageBox("The document was not printed.",
  968.                "Printing", wxOK);
  969.     break;
  970.       }
  971.  
  972.     case WXPRINT_PREVIEW_ALL:
  973.       {
  974.     print_all = 1;
  975. #ifdef wx_msw
  976.       myApp.SetPrintMode(wxPRINT_WINDOWS);
  977. #else 
  978.       // Allow MSW style printing under UNIX
  979.       myApp.SetPrintMode(wxPRINT_POSTSCRIPT);
  980. #endif
  981.     wxPrintData printData;
  982.     if(MSWPrintSetup->orientation == 0) 
  983.       printData.SetOrientation(wxLANDSCAPE);
  984.     else
  985.       printData.SetOrientation(wxPORTRAIT);
  986.  
  987.     if(displaying_list) {
  988.       int yn = wxMessageBox("Print display list objects?",
  989.                 "Program Message", wxYES_NO|wxCENTRE);
  990.       if(yn == wxYES) print_list = 1; else print_list = 0;
  991.     }
  992.     else
  993.       print_list = 0;
  994.     
  995.     // Pass two printout objects: for preview, and possible printing.
  996.     wxPrintPreview *preview = \
  997.       new wxPrintPreview(new wGrocPrint((char *)ProgramName),
  998.                  new wGrocPrint((char *)ProgramName),
  999.                  &printData);
  1000.  
  1001.     if (!preview->Ok()) {
  1002.       delete preview;
  1003.       wxMessageBox("There was a problem previewing.", 
  1004.                "Previewing", wxOK);
  1005.       return;
  1006.     }
  1007.  
  1008.     wxPreviewFrame *frame = new wxPreviewFrame(preview,
  1009.                            this,
  1010.                            (char *)ProgramName,
  1011.                            100, 100, 600, 650);
  1012.     frame->Centre(wxBOTH);
  1013.     frame->Initialize();
  1014.     frame->Show(TRUE);
  1015.     break;
  1016.       }
  1017.  
  1018.     case WXPRINT_PREVIEW_PURCHASING :
  1019.       {
  1020.     print_all = 0;
  1021. #ifdef wx_msw
  1022.       myApp.SetPrintMode(wxPRINT_WINDOWS);
  1023. #else 
  1024.       // Allow MSW style printing under UNIX
  1025.       myApp.SetPrintMode(wxPRINT_POSTSCRIPT);
  1026. #endif
  1027.     wxPrintData printData;
  1028.     if(MSWPrintSetup->orientation == 0) 
  1029.       printData.SetOrientation(wxLANDSCAPE);
  1030.     else
  1031.       printData.SetOrientation(wxPORTRAIT);
  1032.  
  1033.     if(displaying_list) {
  1034.       int yn = wxMessageBox("Print display list objects?",
  1035.                 "Program Message", wxYES_NO|wxCENTRE);
  1036.       if(yn == wxYES) print_list = 1; else print_list = 0;
  1037.     }
  1038.     else
  1039.       print_list = 0;
  1040.  
  1041.     // Pass two printout objects: for preview, and possible printing.
  1042.     wxPrintPreview *preview = \
  1043.       new wxPrintPreview(new wGrocPrint((char *)ProgramName),
  1044.                  new wGrocPrint((char *)ProgramName),
  1045.                  &printData);
  1046.  
  1047.     if (!preview->Ok()) {
  1048.       delete preview;
  1049.       wxMessageBox("There was a problem previewing.", 
  1050.                "Previewing", wxOK);
  1051.       return;
  1052.     }
  1053.  
  1054.     wxPreviewFrame *frame = new wxPreviewFrame(preview,
  1055.                            this,
  1056.                            (char *)ProgramName,
  1057.                            100, 100, 600, 650);
  1058.     frame->Centre(wxBOTH);
  1059.     frame->Initialize();
  1060.     frame->Show(TRUE);
  1061.     break;
  1062.       }
  1063.  
  1064.     case WXPRINT_PRINTER_SETUP:
  1065.       {
  1066. #ifdef wx_msw
  1067.       myApp.SetPrintMode(wxPRINT_WINDOWS);
  1068. #else 
  1069.       // Allow MSW style printing under UNIX
  1070.       myApp.SetPrintMode(wxPRINT_POSTSCRIPT);
  1071. #endif
  1072.     wxPrintData printData;
  1073.  
  1074.     if(MSWPrintSetup->orientation == 0) 
  1075.       printData.SetOrientation(wxLANDSCAPE);
  1076.     else
  1077.       printData.SetOrientation(wxPORTRAIT);
  1078.       
  1079.     wxPrintDialog printerDialog(this, &printData);
  1080.     printerDialog.GetPrintData().SetSetupDialog(TRUE);
  1081.     printerDialog.Show(TRUE);
  1082.     break;
  1083.       }
  1084.  
  1085.     case WXPRINT_PAGE_SETUP:
  1086.       {
  1087.     int xpos=300; int ypos=300; int width=300; 
  1088. #ifdef wx_msw
  1089.     int height=250;
  1090. #else 
  1091.       // Allow MSW style printing under UNIX
  1092.     int height=350;
  1093. #endif
  1094.  
  1095.       wxPageDialog = new wxDialogBox(this, "Page Setup", TRUE,
  1096.                        xpos, ypos, width, height,
  1097.                        wxDEFAULT_DIALOG_STYLE,
  1098.                        "Page Setup");
  1099.     
  1100.     wxPageDialog->Centre();
  1101.     wxPageDialog->NewLine();
  1102.     LppSlider = new wxSlider(wxPageDialog, NULL, "Lines Per Page",
  1103.                  MSWPrintSetup->lines_per_page,
  1104.                  1, 200, 200);
  1105.     wxPageDialog->NewLine();
  1106.     CellSlider = new wxSlider(wxPageDialog, NULL, "Cell Length",
  1107.                   MSWPrintSetup->cell_length,
  1108.                   1, 50, 150);
  1109.     wxPageDialog->NewLine();
  1110.     FsSlider = new wxSlider(wxPageDialog, NULL, "Font Size   ",
  1111.                 MSWPrintSetup->font_size,
  1112.                 1, 50, 150);
  1113.     wxPageDialog->NewLine();
  1114.     LRMSlider = new wxSlider(wxPageDialog, NULL, "Left Margin",
  1115.                 MSWPrintSetup->lr_margin,
  1116.                 1, 20, 150);
  1117.     wxPageDialog->NewLine();
  1118.     wxMessage *om = new wxMessage(wxPageDialog,
  1119.           "The Orientation must match the Printer Setup"); 
  1120.     wxPageDialog->NewLine();
  1121.  
  1122.     OrientationChoice = new wxChoice(wxPageDialog, NULL, "Orientation",
  1123.                      -1, -1, -1, -1, 2, OrChoiceStrings);
  1124.  
  1125.     OrientationChoice->SetSelection(MSWPrintSetup->orientation);
  1126.     wxPageDialog->NewLine();
  1127.     
  1128.     FontChoice = new wxChoice(wxPageDialog, NULL, "Font",
  1129.                   -1, -1, -1, -1, 6, FontChoiceStrings);
  1130.     FontChoice->SetSelection(MSWPrintSetup->font);
  1131.     wxPageDialog->NewLine();
  1132.     
  1133.         btn_pdb_close = new wxButton(wxPageDialog, (wxFunction)&page_btn_proc,
  1134.                      "Close", 10, -1, -1, -1);
  1135.         btn_pdb_close->SetClientData((char*)PAGE_DIALOG_BUTTON_CLOSE);
  1136.  
  1137.     btn_pdb_accept = new wxButton(wxPageDialog, (wxFunction)&page_btn_proc,
  1138.                      "Accept", 60, -1, -1, -1);
  1139.     btn_pdb_accept->SetClientData((char*)PAGE_DIALOG_BUTTON_ACCEPT);
  1140.     
  1141.     btn_pdb_cancel = new wxButton(wxPageDialog, (wxFunction)&page_btn_proc,
  1142.                      "Cancel", 118, -1, -1, -1);
  1143.     btn_pdb_cancel->SetClientData((char*)PAGE_DIALOG_BUTTON_CANCEL);
  1144.     
  1145.     btn_pdb_default = new wxButton(wxPageDialog,
  1146.                        (wxFunction)&page_btn_proc,
  1147.                        "Default", 175, -1, -1, -1);
  1148.     btn_pdb_default->SetClientData((char*)PAGE_DIALOG_BUTTON_DEFAULT);
  1149.  
  1150.     wxPageDialog->Show(TRUE);
  1151.     break;
  1152.       }
  1153. #endif //  __USE_MSW_PRINTING__
  1154.     
  1155.     case PRINT_POSTSCRIPT_PURCHASING:
  1156.       ps_print_all = 0;
  1157.       PostScriptPrint(*textWin);
  1158.       break;
  1159.  
  1160.     case PRINT_POSTSCRIPT_ALL:
  1161.       ps_print_all = 1;
  1162.       PostScriptPrint(*textWin);
  1163.       break;
  1164.  
  1165.     case PRINT_ASCII_PURCHASING:
  1166.       as_print_all = 0;
  1167.       ASCIIPrintAll(*textWin);
  1168.       break;
  1169.  
  1170.     case PRINT_ASCII_ALL:
  1171.       as_print_all = 1;
  1172.       ASCIIPrintAll(*textWin);
  1173.       break;
  1174.  
  1175.     case VIEW_CLEAR:
  1176.       Clear(*textWin);
  1177.       break;
  1178.  
  1179.     case VIEW_TOTAL_PURCHASING :
  1180.       view_all = 0;
  1181.       ViewTotals(*textWin);
  1182.       break;
  1183.  
  1184.     case VIEW_TOTAL_ALL :
  1185.       view_all = 1;
  1186.       ViewTotals(*textWin);
  1187.       break;
  1188.  
  1189.     case HELP_ABOUT: {
  1190.       char *s = VerNumber();
  1191.       UString mesg(ProgramName);
  1192.       mesg = mesg + "\nVersion Number " + s;
  1193.       wxMessageBox(mesg.c_str(), "About", wxOK|wxCENTRE);
  1194.       break;
  1195.     }
  1196.     
  1197.     case HELP_USERLEVEL: {
  1198.       UString mesg;
  1199.       if(AdminRights) {
  1200.     mesg = mesg + "You have Admin User Privileges\n" + \
  1201.       "As defined in the " + DefaultCfgFile + " config file\n";
  1202.     wxMessageBox(mesg.c_str(), "Access Level", wxOK|wxCENTRE);
  1203.       }
  1204.       else {
  1205.     mesg = mesg + "You do not have Admin User Privileges\n" + \
  1206.       "As defined in the " + DefaultCfgFile + " config file\n";
  1207.     wxMessageBox(mesg.c_str(), "Access Level", wxOK|wxCENTRE);
  1208.       }
  1209.       break;
  1210.     }
  1211.   }
  1212. }
  1213.  
  1214. void MyTextWindow::OnChar(wxKeyEvent& event)
  1215. {
  1216.   if(event.keyCode == CONTROL('x')) {
  1217.     Cut(); 
  1218.     frame->SetStatusText("Cut text and copied to clipboard");
  1219.   }
  1220.  
  1221.   if(event.keyCode == CONTROL('c')) {
  1222.     Copy(); 
  1223.     frame->SetStatusText("Copied text from clipboard");
  1224.   }
  1225.  
  1226.   if(event.keyCode == CONTROL('v')) {
  1227.     Paste(); 
  1228.     frame->SetStatusText("Pasted text from clipboard");
  1229.   }
  1230.  
  1231.   wxTextWindow::OnChar(event);  // Process the default behavior
  1232. }
  1233.  
  1234. void MyFrame::OnSize(int w, int h)
  1235. {
  1236.   wxFrame::OnSize(w, h);
  1237. }
  1238.  
  1239. MyText::MyText(wxPanel *parent, wxFunction func, char *label,
  1240.              char *value, int x, int y, int width, int height ,
  1241.              long style, char *name) :
  1242.   wxText(parent, func, label, value,x, y, width, height , style, name)
  1243. {
  1244.   item_name = brand = store = price = quantity = purchasing = line_total = 0; 
  1245. }
  1246.  
  1247. MyText::~MyText()
  1248. {
  1249.   if(item_name) delete item_name;
  1250.   if(brand) delete brand;
  1251.   if(store) delete store;
  1252.   if(price) delete price;
  1253.   if(quantity) delete quantity;
  1254.   if(purchasing) delete purchasing;
  1255.   if(line_total) delete line_total;
  1256. }
  1257.  
  1258. void Clear(MyTextWindow& textWin)
  1259. {
  1260.   textWin.Clear();
  1261. }
  1262.  
  1263. char *VerNumber()
  1264. // Version number for this windows program. Edit the version.h
  1265. // file to change this program's version number
  1266. {
  1267.  char sbuffer[sbuffer_len];
  1268.  sprintf(sbuffer, "%.3f", VersionNumber); 
  1269.  int len = strlen(sbuffer);
  1270.  char *s = new char[len+1];
  1271.  s[len+1] = '\0';
  1272.  strcpy(s, sbuffer);
  1273.  return s;
  1274. }
  1275.  
  1276. void text_proc(wxText &but, wxCommandEvent &event)
  1277. {
  1278.   // Nothing to do
  1279. }
  1280.  
  1281. void AddBtnProc(wxButton& but, wxCommandEvent& event)
  1282. {
  1283.   UString sbuf; // Character string input buffer
  1284.   long tag = (long)but.GetClientData() ;
  1285.   double price;
  1286.   long quantity;
  1287.   int i, rv;
  1288.   char purchasing;
  1289.   char sbuffer[sbuffer_len];
  1290.   FLOAT64 line_total;
  1291.   
  1292.   if(tag == ADD_BUTTON_ADD) {
  1293.     UString item_name;
  1294.     UString brand;
  1295.     UString store;
  1296.  
  1297.     item_name = frame->addText->item_name->GetValue();
  1298.     brand = frame->addText->brand->GetValue();
  1299.     store = frame->addText->store->GetValue();
  1300.     price = atof(frame->addText->price->GetValue());
  1301.     quantity = atoi(frame->addText->quantity->GetValue());
  1302.     rv = add_PurchasingChoice->GetSelection();
  1303.     
  1304.     // Remove any leading space from the key name entry
  1305.     int offset = item_name.Find(" ");
  1306.     if(offset == 0) item_name.DeleteAt(offset, 1);
  1307.     
  1308.     if(item_name == "") { // Check for a key name valid input
  1309.       sbuf = sbuf + "Invalid " + KeyName + " input!";
  1310.       frame->textWin->WriteText(sbuf.c_str());
  1311.       frame->textWin->WriteText("\n");
  1312.       Error->Message(sbuf.c_str());
  1313.       return;
  1314.     }
  1315.  
  1316.     Grocery grocery(DB);
  1317.     grocery.SetName(item_name);
  1318.     FAU addr = grocery.FindObject();
  1319.     
  1320.     if(addr) {
  1321.       sbuf = sbuf + "An Entry for " + item_name +  " already exists!";
  1322.       frame->textWin->WriteText(sbuf.c_str());
  1323.       frame->textWin->WriteText("\n");
  1324.       Error->Message(sbuf.c_str());
  1325.       return;
  1326.     }
  1327.  
  1328.     agrocery->SetName(item_name.c_str());
  1329.     agrocery->SetBrand(brand.c_str());
  1330.     agrocery->SetStore(store.c_str());
  1331.     agrocery->SetPrice(price);
  1332.     agrocery->SetQuantity(quantity);
  1333.  
  1334.     if(rv == 0)
  1335.       agrocery->SetPurchasing('N');
  1336.     else
  1337.       agrocery->SetPurchasing('Y');
  1338.  
  1339.     line_total = agrocery->GetPrice() * agrocery->GetQuantity();
  1340.     agrocery->SetLineTotal(line_total);
  1341.     
  1342.     addr = agrocery->AddObject(0); // Write the object to the file
  1343.  
  1344.     if(!addr) {
  1345.       sbuf = sbuf + "Could not add Entry for " + agrocery->GetName();
  1346.       frame->textWin->WriteText(sbuf.c_str());
  1347.       frame->textWin->WriteText("\n");
  1348.       Error->Message(sbuf.c_str());
  1349.       return;
  1350.     }
  1351.  
  1352.     sbuf = sbuf + "Added Entry for " + agrocery->GetName();
  1353.     frame->textWin->WriteText(sbuf.c_str());
  1354.     frame->textWin->WriteText("\n");
  1355.     ClearAddPanel();
  1356.  
  1357.     if(displaying_list) {
  1358.       InMemCopy inmemcopy(agrocery->GetName(), agrocery->ObjectAddress(),
  1359.               agrocery->GetClassID());
  1360.       dllist->StoreNode(inmemcopy);
  1361.     }
  1362.   }
  1363.   
  1364.   if(tag == ADD_BUTTON_CANCEL) {
  1365.     ClearAddPanel();
  1366.     return;
  1367.   }
  1368.  
  1369.   if(tag == ADD_BUTTON_CLOSE) {
  1370.     APanelFrame->Show(FALSE);
  1371.     return;
  1372.   }
  1373.  
  1374.   if(tag == ADD_BUTTON_REVERT) {
  1375.     if(agrocery->GetName())
  1376.       frame->addText->item_name->SetValue(agrocery->GetName());
  1377.       if(agrocery->GetBrand())
  1378.     frame->addText->brand->SetValue(agrocery->GetBrand());
  1379.       if(agrocery->GetStore())
  1380.     frame->addText->store->SetValue(agrocery->GetStore());
  1381.       price = agrocery->GetPrice();
  1382.       sprintf(sbuffer, "%.2f", price);
  1383.       frame->addText->price->SetValue(sbuffer);
  1384.       quantity = agrocery->GetQuantity();
  1385.       for(i = 0; i < sbuffer_len; i++) sbuffer[i] = '\0';
  1386.       sprintf(sbuffer, "%d", quantity);
  1387.       frame->addText->quantity->SetValue(sbuffer);
  1388.       purchasing = agrocery->GetPurchasing();
  1389.       if(purchasing == 'N' || purchasing == 'n')
  1390.     add_PurchasingChoice->SetSelection(0);
  1391.       else
  1392.     add_PurchasingChoice->SetSelection(1);
  1393.     return;
  1394.   }
  1395. }
  1396.  
  1397. void ClearAddPanel()
  1398. {
  1399.   frame->addText->item_name->SetValue("");
  1400.   frame->addText->brand->SetValue("");
  1401.   frame->addText->store->SetValue("");
  1402.   frame->addText->price->SetValue("");
  1403.   frame->addText->quantity->SetValue("");
  1404.   add_PurchasingChoice->SetSelection(0);
  1405. }
  1406.  
  1407. void Add(MyTextWindow &textWin)
  1408. {
  1409.   if(!AdminRights) {
  1410.       wxMessageBox("You do not have Admin User Privileges\n",
  1411.            "Program Message", wxOK|wxCENTRE);
  1412.     return;
  1413.   }
  1414.     
  1415.   textWin.Clear();
  1416.   textWin << "Adding objects to database..." << "\n";
  1417.   textWin << "\n";
  1418.   
  1419.   
  1420.   APanelFrame->Show(TRUE); // Show the Add Panel Frame
  1421. }
  1422.  
  1423. void ChBtnProc(wxButton& but, wxCommandEvent& event)
  1424. {
  1425.   UString sbuf, item_name; // Character input string buffer
  1426.   long tag = (long)but.GetClientData() ;
  1427.   double price, line_total;
  1428.   long quantity;
  1429.   int i, rv, offset;
  1430.   char purchasing;
  1431.   char sbuffer[sbuffer_len];
  1432.   
  1433.   if(tag == CHANGE_BUTTON_SH) {  
  1434.     item_name = frame->changeText->item_name->GetValue();
  1435.  
  1436.     // Remove any leading space from the key name entry
  1437.     offset = item_name.Find(" ");
  1438.     if(offset == 0) item_name.DeleteAt(offset, 1);
  1439.     
  1440.     if(item_name == "") { // Check for a key name valid input
  1441.       sbuf = sbuf + "Invalid " + KeyName + " input!";
  1442.       frame->textWin->WriteText(sbuf.c_str());
  1443.       frame->textWin->WriteText("\n");
  1444.       Error->Message(sbuf.c_str());
  1445.       btn_ch_cm->Enable(0);
  1446.       return;
  1447.     }
  1448.     
  1449.     Grocery grocery(DB);
  1450.     grocery.SetName(item_name);
  1451.     FAU addr = grocery.FindObject();
  1452.  
  1453.     if(!addr) {
  1454.       sbuf = sbuf + "Could not find an entry for " + item_name;
  1455.       frame->textWin->WriteText(sbuf.c_str());
  1456.       frame->textWin->WriteText("\n");
  1457.       Error->Message(sbuf.c_str());
  1458.       btn_ch_cm->Enable(0);
  1459.       return;
  1460.     }
  1461.  
  1462.     cgrocery->Copy(grocery);
  1463.     
  1464.     if(cgrocery->GetBrand())
  1465.       frame->changeText->brand->SetValue(cgrocery->GetBrand());
  1466.     if(cgrocery->GetStore())
  1467.       frame->changeText->store->SetValue(cgrocery->GetStore());
  1468.     price = cgrocery->GetPrice();
  1469.     sprintf(sbuffer, "%.2f", price);
  1470.     frame->changeText->price->SetValue(sbuffer);
  1471.     quantity = cgrocery->GetQuantity();
  1472.     for(i = 0; i < sbuffer_len; i++) sbuffer[i] = '\0';
  1473.     sprintf(sbuffer, "%d", quantity);
  1474.     frame->changeText->quantity->SetValue(sbuffer);
  1475.     purchasing = cgrocery->GetPurchasing();
  1476.     if(purchasing == 'N' || purchasing == 'n')
  1477.       ch_PurchasingChoice->SetSelection(0);
  1478.     else
  1479.       ch_PurchasingChoice->SetSelection(1);
  1480.     line_total = cgrocery->GetLineTotal();
  1481.     for(i = 0; i < sbuffer_len; i++) sbuffer[i] = '\0';
  1482.     sprintf(sbuffer, "%.2f", line_total);
  1483.     frame->changeText->line_total->SetValue(sbuffer);
  1484.     frame->changeText->line_total->SetEditable(FALSE);
  1485.     btn_ch_cm->Enable(1); // Enable the commit button
  1486.   }
  1487.  
  1488.   if(tag == CHANGE_BUTTON_CM) {
  1489.     item_name = frame->changeText->item_name->GetValue();
  1490.  
  1491.     // Remove any leading space from the key name entry
  1492.     offset = item_name.Find(" ");
  1493.     if(offset == 0) item_name.DeleteAt(offset, 1);
  1494.     
  1495.     if(item_name == "") { // Check for a key name valid input
  1496.       sbuf = sbuf + "Invalid " + KeyName + " input!";
  1497.       frame->textWin->WriteText(sbuf.c_str());
  1498.       frame->textWin->WriteText("\n");
  1499.       Error->Message(sbuf.c_str());
  1500.       btn_ch_cm->Enable(0);
  1501.       return;
  1502.     }
  1503.  
  1504.     Grocery changed(DB); // Buffer used to store changes
  1505.     changed.SetName(frame->changeText->item_name->GetValue());
  1506.     changed.SetBrand(frame->changeText->brand->GetValue());
  1507.     changed.SetStore(frame->changeText->store->GetValue());
  1508.     price = atof(frame->changeText->price->GetValue());
  1509.     changed.SetPrice(price);
  1510.     quantity = atoi(frame->changeText->quantity->GetValue());
  1511.     changed.SetQuantity(quantity);
  1512.     rv = ch_PurchasingChoice->GetSelection();
  1513.     if(rv == 0)
  1514.       changed.SetPurchasing('N');
  1515.     else
  1516.       changed.SetPurchasing('Y');
  1517.     FLOAT64 ltotal = changed.GetPrice() * changed.GetQuantity();
  1518.     changed.SetLineTotal(ltotal);
  1519.  
  1520.     // Disable the commit button after changing the object
  1521.     btn_ch_cm->Enable(0);
  1522.  
  1523.     if(changed.FullCompare(*cgrocery)) { // The object has not changed
  1524.       sbuf = sbuf + "No changes to commit for " + cgrocery->GetName();
  1525.       frame->textWin->WriteText(sbuf.c_str());
  1526.       frame->textWin->WriteText("\n");
  1527.       Error->Message(sbuf.c_str());
  1528.       ClearChangePanel();
  1529.  
  1530.       if(displaying_list) { //Objects are being displayed
  1531.     if(!dllist->IsEmpty()) DPanelFrame->Show(TRUE);
  1532.       }
  1533.       btn_ch_cm->Enable(0);
  1534.       return;
  1535.     }
  1536.  
  1537.     UString key_name(changed.GetName());
  1538.     UString old_key_name(cgrocery->GetName());
  1539.  
  1540.     // If the key name is changed, ensure no duplicates are added
  1541.     if(key_name != old_key_name) {
  1542.       if((__LWORD__)changed.FindObject()) {
  1543.     sbuf = sbuf + "An Entry for " + key_name + " already exists!";
  1544.     frame->textWin->WriteText(sbuf.c_str());
  1545.     frame->textWin->WriteText("\n");
  1546.     Error->Message(sbuf.c_str());
  1547.     if(displaying_list) { // Objects are being displayed
  1548.       if(!dllist->IsEmpty()) DPanelFrame->Show(TRUE);
  1549.     }
  1550.     btn_ch_cm->Enable(0);
  1551.     return;
  1552.       }
  1553.     }
  1554.  
  1555.     FAU oa = cgrocery->ObjectAddress(); // Record address before deleting
  1556.     cgrocery->DeleteObject(); // Remove the object  
  1557.     changed.AddObject(0); // Add the changed object back to the database
  1558.  
  1559.     sbuf = sbuf + "Commited changes for " + changed.GetName();
  1560.     frame->textWin->WriteText(sbuf.c_str());
  1561.     frame->textWin->WriteText("\n");
  1562.     ClearChangePanel();
  1563.  
  1564.     // Update any list entries for display panel
  1565.     if(displaying_list) { // Objects are being displayed
  1566.       if(dllist->IsEmpty()) {
  1567.     displaying_list = 0;
  1568.     DPanelFrame->Show(FALSE);
  1569.     return;
  1570.       }
  1571.       InMemCopy inmemcopy(cgrocery->GetName(), oa, cgrocery->GetClassID());
  1572.       DNode<InMemCopy> *prevptr = dllistptr;
  1573.       dllistptr = (DNode<InMemCopy> *)dllist->Find(inmemcopy);
  1574.       if(dllistptr) {
  1575.     dllistptr->Data.key = changed.GetName();    
  1576.     dllistptr->Data.object_address = changed.ObjectAddress();
  1577.     dllistptr->Data.class_id = changed.GetClassID();
  1578.     if(displaying_list) {
  1579.       DPanelFrame->Show(TRUE);
  1580.       DisplayObject(changed);
  1581.     }
  1582.       }
  1583.       else {
  1584.        dllistptr = prevptr;
  1585.        dllistptr->Data.key = changed.GetName();    
  1586.        dllistptr->Data.object_address = changed.ObjectAddress();
  1587.        dllistptr->Data.class_id = changed.GetClassID();
  1588.        if(displaying_list) {
  1589.      DPanelFrame->Show(TRUE);
  1590.      DisplayObject(changed);
  1591.        }
  1592.       }
  1593.     }
  1594.   }
  1595.     
  1596.   if(tag == CHANGE_BUTTON_CANCEL) {
  1597.     ClearChangePanel();
  1598.     if(displaying_list) { // Objects are being displayed
  1599.       if(!dllist->IsEmpty()) DPanelFrame->Show(TRUE);
  1600.     }
  1601.     btn_ch_cm->Enable(0);
  1602.     return;
  1603.   }
  1604.  
  1605.   if(tag == CHANGE_BUTTON_CLOSE) {
  1606.     ClearChangePanel();
  1607.     CPanelFrame->Show(FALSE);
  1608.     btn_ch_cm->Enable(0);
  1609.     return;
  1610.   }
  1611.  
  1612.   if(tag == CHANGE_BUTTON_REVERT) {
  1613.     if(cgrocery->GetName())
  1614.       frame->changeText->item_name->SetValue(cgrocery->GetName());
  1615.       if(cgrocery->GetBrand())
  1616.     frame->changeText->brand->SetValue(cgrocery->GetBrand());
  1617.       if(cgrocery->GetStore())
  1618.     frame->changeText->store->SetValue(cgrocery->GetStore());
  1619.       price = cgrocery->GetPrice();
  1620.       sprintf(sbuffer, "%.2f", price);
  1621.       frame->changeText->price->SetValue(sbuffer);
  1622.       quantity = cgrocery->GetQuantity();
  1623.       for(int i = 0; i < sbuffer_len; i++) sbuffer[i] = '\0';
  1624.       sprintf(sbuffer, "%d", quantity);
  1625.       frame->changeText->quantity->SetValue(sbuffer);
  1626.       purchasing = cgrocery->GetPurchasing();
  1627.       if(purchasing == 'N' || purchasing == 'n')
  1628.     ch_PurchasingChoice->SetSelection(0);
  1629.       else
  1630.     ch_PurchasingChoice->SetSelection(1);
  1631.       line_total = cgrocery->GetPrice() * cgrocery->GetQuantity();
  1632.       for(i = 0; i < sbuffer_len; i++) sbuffer[i] = '\0';
  1633.       sprintf(sbuffer, "%.2f", line_total);
  1634.       frame->changeText->line_total->SetValue(sbuffer);
  1635.       btn_ch_cm->Enable(0);
  1636.       return;
  1637.   }
  1638. }
  1639.  
  1640. void ClearChangePanel()
  1641. {
  1642.   frame->changeText->item_name->SetValue("");
  1643.   frame->changeText->brand->SetValue("");
  1644.   frame->changeText->store->SetValue("");
  1645.   frame->changeText->price->SetValue("");
  1646.   frame->changeText->quantity->SetValue("");
  1647.   ch_PurchasingChoice->SetSelection(0);
  1648.   frame->changeText->line_total->SetValue("");
  1649. }
  1650.  
  1651. void Change(MyTextWindow &textWin)
  1652. {
  1653.   if(!AdminRights) {
  1654.       wxMessageBox("You do not have Admin User Privileges\n",
  1655.            "Program Message", wxOK|wxCENTRE);
  1656.     return;
  1657.   }
  1658.  
  1659.   textWin.Clear();
  1660.   textWin << "Changing objects in database..." << "\n";
  1661.   textWin << "\n";
  1662.   
  1663.   CPanelFrame->Show(TRUE); // Show the Add Panel Frame
  1664. }
  1665.  
  1666. void Remove(MyTextWindow &textWin, char *keyNM)
  1667. {
  1668.   if(!AdminRights) {
  1669.     wxMessageBox("You do not have Admin User Privileges\n",
  1670.          "Program Message", wxOK|wxCENTRE);
  1671.     return;
  1672.   }
  1673.  
  1674.   textWin.Clear();
  1675.   textWin << "Removing object from database..." << "\n";
  1676.  
  1677.   UString item_name;
  1678.   UString comp;
  1679.   char *buf;
  1680.   
  1681.   if(!keyNM) {
  1682.     comp = comp + "Enter " + KeyName + " to Remove:";
  1683.     buf = wxGetTextFromUser(comp.c_str(), "String Input");
  1684.  
  1685.     if(!buf) {
  1686.       textWin << "Canceled." << "\n";
  1687.       return;
  1688.     }
  1689.  
  1690.     item_name = buf;
  1691.     
  1692.     // Remove any leading space from the key name entry
  1693.     int offset = item_name.Find(" ");
  1694.     if(offset == 0) item_name.DeleteAt(offset, 1);
  1695.   
  1696.     if(item_name == "") { // Check for a key name valid input
  1697.       comp.DeleteAt(0, comp.length());
  1698.       comp = comp + "Invalid " + KeyName + " input!";
  1699.       frame->textWin->WriteText(comp.c_str());
  1700.       frame->textWin->WriteText("\n");
  1701.       Error->Message(comp.c_str());
  1702.       return;
  1703.     }
  1704.   }  
  1705.   else
  1706.     item_name = keyNM; // Key name memeber
  1707.  
  1708.   Grocery grocery(DB);
  1709.   grocery.SetName(item_name);
  1710.  
  1711.   FAU addr = grocery.FindObject();
  1712.   
  1713.   if(!addr) { 
  1714.     comp.DeleteAt(0, comp.length());
  1715.     comp = comp + "Could not find an entry for: " + item_name.c_str();
  1716.     Error->Message(comp.c_str());
  1717.     textWin << comp.c_str() << "\n";
  1718.     return;
  1719.   }
  1720.  
  1721.   int yn = wxMessageBox("Are you sure you want to remove",
  1722.                "Program Message", wxYES_NO|wxCENTRE);
  1723.  
  1724.   if(yn == wxNO) return;
  1725.   
  1726.  
  1727.   InMemCopy listdata(grocery.GetName(), grocery.ObjectAddress(),
  1728.              grocery.GetClassID());
  1729.  
  1730.   grocery.DeleteObject();
  1731.   textWin << "Removed entry for: " << item_name.c_str() << "\n";
  1732.  
  1733.   // Update display item panel list 
  1734.   if(displaying_list) {
  1735.     if(dllist->IsEmpty()) {
  1736.       displaying_list = 0;
  1737.       DPanelFrame->Show(TRUE);
  1738.       return;
  1739.     }
  1740.     DNode<InMemCopy> *dllptr = 0;
  1741.     dllptr = (DNode<InMemCopy> *)dllist->Find(listdata);
  1742.     if(dllptr) {
  1743.       dllist->Delete(dllptr);
  1744.       wxCommandEvent wxevent1(wxEVENT_TYPE_BUTTON_COMMAND);
  1745.       DsBtnProc(*btn_ds_nx, wxevent1); // Simulate pushing the Next Button
  1746.     }
  1747.   }
  1748. }
  1749.  
  1750. void DsBtnProc(wxButton& but, wxCommandEvent& event)
  1751. {
  1752.   char *sbuf = 0; // Character string buffer
  1753.   long tag = (long)but.GetClientData() ;
  1754.   Grocery grocery(DB);
  1755.   
  1756.   if(tag == DISPLAY_BUTTON_NX) {
  1757.     if(!dllistptr) return;
  1758.     if(!dllist) return;
  1759.     if(dllist->IsEmpty()) {
  1760.       ClearDisplayPanel();
  1761.       wxMessageBox("The display list is empty\n",
  1762.            "Program Message", wxOK|wxCENTRE);
  1763.       return;
  1764.     }
  1765.     else
  1766.       dllistptr = dllistptr->GetNext();
  1767.  
  1768.     if(!dllist->IsHeader(dllistptr)) {
  1769.       grocery.ReadObject(dllistptr->Data.object_address);
  1770.       DisplayObject(grocery);
  1771.     }
  1772.     else {
  1773.       wxMessageBox("Reached the end of the list\n",
  1774.            "Program Message", wxOK|wxCENTRE);
  1775.       dllistptr = dllist->GetFront();
  1776.       grocery.ReadObject(dllistptr->Data.object_address);
  1777.       DisplayObject(grocery);
  1778.     }
  1779.   }
  1780.  
  1781.   if(tag == DISPLAY_BUTTON_PREV) {
  1782.     if(!dllistptr) return;
  1783.     if(!dllist) return;
  1784.     if(dllist->IsEmpty()) {
  1785.       ClearDisplayPanel();
  1786.       wxMessageBox("The display list is empty\n",
  1787.            "Program Message", wxOK|wxCENTRE);
  1788.       return;
  1789.     }
  1790.     else
  1791.       dllistptr = dllistptr->GetPrior();
  1792.  
  1793.     if(!dllist->IsHeader(dllistptr)) {
  1794.       grocery.ReadObject(dllistptr->Data.object_address);
  1795.       DisplayObject(grocery);
  1796.     }
  1797.     else {
  1798.       wxMessageBox("Reached the beginning of the list\n",
  1799.            "Program Message", wxOK|wxCENTRE);
  1800.       dllistptr = dllist->GetBack();
  1801.       grocery.ReadObject(dllistptr->Data.object_address);
  1802.       DisplayObject(grocery);
  1803.     }
  1804.   }
  1805.  
  1806.   if(tag == DISPLAY_BUTTON_CHANGE) {
  1807.     if(!AdminRights) {
  1808.       wxMessageBox("You do not have Admin User Privileges\n",
  1809.            "Program Message", wxOK|wxCENTRE);
  1810.       return;
  1811.     }
  1812.  
  1813.     if(dllist->IsEmpty()) {
  1814.       wxMessageBox("The display list is empty\n",
  1815.            "Program Message", wxOK|wxCENTRE);
  1816.       return;
  1817.     }
  1818.  
  1819.     if(!dllist->IsEmpty()) {
  1820.       grocery.ReadObject(dllistptr->Data.object_address);
  1821.       cgrocery->Copy(grocery);
  1822.     }
  1823.     else
  1824.       cgrocery->Copy(*dgrocery);
  1825.     frame->changeText->item_name->SetValue(cgrocery->GetName());
  1826.     wxCommandEvent wxevent(wxEVENT_TYPE_BUTTON_COMMAND);
  1827.     ChBtnProc(*btn_ch_sh, wxevent); // Simulate pushing the Search Button
  1828.     CPanelFrame->Show(TRUE); // Show the Change Panel Frame
  1829.   }
  1830.  
  1831.   if(tag == DISPLAY_BUTTON_CLOSE) {
  1832.     ClearDisplayPanel();
  1833.     displaying_list = 0;
  1834.     DPanelFrame->Show(FALSE);
  1835.     CPanelFrame->Show(FALSE);
  1836.     if(!dllist->IsEmpty()) dllist->Clear();
  1837.     return;
  1838.   }
  1839.  
  1840.   if(tag == DISPLAY_BUTTON_REMOVE) {
  1841.     if(!AdminRights) {
  1842.       wxMessageBox("You do not have Admin User Privileges\n",
  1843.            "Program Message", wxOK|wxCENTRE);
  1844.       return;
  1845.     }
  1846.  
  1847.     if(dllist->IsEmpty()) {
  1848.       wxMessageBox("The display list is empty\n",
  1849.            "Program Message", wxOK|wxCENTRE);
  1850.       return;
  1851.     }
  1852.     else
  1853.       Remove(*frame->textWin, dgrocery->GetName());
  1854.   }
  1855. }
  1856.  
  1857. void ClearDisplayPanel()
  1858. {
  1859.   frame->displayText->item_name->SetValue("");
  1860.   frame->displayText->brand->SetValue("");
  1861.   frame->displayText->store->SetValue("");
  1862.   frame->displayText->price->SetValue("");
  1863.   frame->displayText->quantity->SetValue("");
  1864.   frame->displayText->purchasing->SetValue("");
  1865.   frame->displayText->line_total->SetValue("");
  1866. }
  1867.  
  1868. void DisplayObject(Grocery &grocery)
  1869. {
  1870.   dgrocery->Copy(grocery); // Initialize global display object
  1871.   double price, line_total;
  1872.   long quantity;
  1873.   int i;
  1874.   char purchasing;
  1875.   char sbuffer[sbuffer_len];
  1876.  
  1877.   if(grocery.GetName())
  1878.       frame->displayText->item_name->SetValue(grocery.GetName());
  1879.   if(grocery.GetBrand())
  1880.     frame->displayText->brand->SetValue(grocery.GetBrand());
  1881.   if(grocery.GetStore())
  1882.     frame->displayText->store->SetValue(grocery.GetStore());
  1883.  
  1884.   price = grocery.GetPrice();
  1885.   sprintf(sbuffer, "%.2f", price);
  1886.   frame->displayText->price->SetValue(sbuffer);
  1887.   
  1888.   quantity = grocery.GetQuantity();
  1889.   for(i = 0; i < sbuffer_len; i++) sbuffer[i] = '\0';
  1890.   sprintf(sbuffer, "%d", quantity);
  1891.   frame->displayText->quantity->SetValue(sbuffer);
  1892.  
  1893.   purchasing = grocery.GetPurchasing();
  1894.   if(purchasing == 'N' || purchasing == 'n')
  1895.     frame->displayText->purchasing->SetValue("No");
  1896.   else
  1897.     frame->displayText->purchasing->SetValue("Yes");
  1898.  
  1899.   line_total = grocery.GetLineTotal();
  1900.   for(i = 0; i < sbuffer_len; i++) sbuffer[i] = '\0';
  1901.   sprintf(sbuffer, "%.2f", line_total);
  1902.   frame->displayText->line_total->SetValue(sbuffer);
  1903.  
  1904.   displaying_list = 1;
  1905.   DPanelFrame->Show(TRUE);
  1906. }
  1907.  
  1908. void LoadGKeys(EntryKey &e)
  1909. // Visit function used to load the btree keys into memory
  1910. {
  1911.   Grocery grocery(DB);
  1912.   char purchasing;
  1913.  
  1914.   grocery.ReadObject(e.object_address);
  1915.   
  1916.   if(purchase_all) {
  1917.     InMemCopy inmemcopy(e.key, e.object_address, e.class_id);
  1918.     dllist->StoreNode(inmemcopy);
  1919.     grand_total += grocery.GetLineTotal();
  1920.     num_objects++;
  1921.   }
  1922.   else {
  1923.     purchasing = grocery.GetPurchasing();
  1924.     if(purchasing == 'Y' || purchasing == 'y') {
  1925.       InMemCopy inmemcopy(e.key, e.object_address, e.class_id);
  1926.       dllist->StoreNode(inmemcopy);
  1927.       grand_total += grocery.GetLineTotal();
  1928.       num_objects++;
  1929.     }
  1930.   }
  1931. }
  1932.  
  1933. int LoadIndexKeys(int load_all)
  1934. {
  1935.   grand_total = 0;
  1936.   num_objects = 0;
  1937.   purchase_all = load_all;
  1938.   dllist->Clear();
  1939.   BtreeWalker btw(DB->Index());
  1940.   btw.Sort(LoadGKeys);
  1941.   if(num_objects > 0) print_list = 1;
  1942.   return num_objects;
  1943. }
  1944.  
  1945. void ReOrderDisplayList()
  1946. {
  1947.   if(dllist->IsEmpty()) return;
  1948.   Grocery grocery(DB);
  1949.   char purchasing;
  1950.   dllistptr = dllist->GetFront();
  1951.   DLList<InMemCopy> tmp_list;
  1952.   grand_total = 0;
  1953.   num_objects = 0;
  1954.   
  1955.   while(!dllist->IsHeader(dllistptr)) { 
  1956.     grocery.ReadObject(dllistptr->Data.object_address);
  1957.     purchasing = grocery.GetPurchasing();
  1958.     if(purchasing == 'Y' || purchasing == 'y') {
  1959.       grand_total += grocery.GetLineTotal();
  1960.       num_objects++;
  1961.       tmp_list.StoreNode(dllistptr->Data);
  1962.     }
  1963.     dllistptr = dllistptr->GetNext();
  1964.   }
  1965.  
  1966.   dllist->Copy(tmp_list);
  1967.   
  1968.   // Always close the display panel after reordering the list
  1969.   if(displaying_list == 1) { 
  1970.     displaying_list = 0;
  1971.     DPanelFrame->Show(FALSE);
  1972.   }
  1973. }
  1974.  
  1975. void DisplayDB(MyTextWindow &textWin)
  1976. {
  1977.   Grocery grocery(DB);
  1978.   char purchasing;
  1979.   
  1980.   textWin.Clear();
  1981.     
  1982.   if(DB->RebuildIndex()) {
  1983.     textWin << "\n";
  1984.     textWin << "Displaying the database objects." << "\n";
  1985.     textWin << "The index file needs to be rebuilt." << "\n";
  1986.     return;
  1987.   }
  1988.  
  1989.   num_objects = LoadIndexKeys(display_all);
  1990.   
  1991.   if(display_all == 0) {
  1992.     textWin << "Displaying objects select for purchase only." << "\n";
  1993.     if(num_objects == 0) {
  1994.       textWin << "Nothing to display." << "\n";
  1995.       return;
  1996.     }
  1997.     textWin << "Displaying " << num_objects << " objects..." << "\n";
  1998.   }
  1999.   else {
  2000.     textWin << "Displaying all objects in the database." << "\n";
  2001.     if(num_objects == 0) {
  2002.       textWin << "Nothing to display." << "\n";
  2003.       return;
  2004.     }
  2005.     textWin << "Displaying " << num_objects << " objects..." << "\n";
  2006.   }
  2007.  
  2008.   dllistptr = dllist->GetFront();
  2009.   
  2010.   // Display the first object
  2011.   grocery.ReadObject(dllistptr->Data.object_address);    
  2012.   if(display_all == 0) {
  2013.     purchasing = grocery.GetPurchasing();
  2014.     if(purchasing == 'N' || purchasing == 'n') return;
  2015.   }
  2016.   DisplayObject(grocery);
  2017. }
  2018.  
  2019. void FindBy(MyTextWindow &textWin, const char *MemberName, GrocDBItem item)
  2020. {
  2021.   textWin.Clear();
  2022.   textWin << "Searching for object by " << (char *)MemberName << "\n";
  2023.   UString comp;
  2024.  
  2025.   comp = comp + "Enter complete string or use " + WildCard + \
  2026.     " for a wild card:";
  2027.   
  2028.   char *buf = wxGetTextFromUser(comp.c_str(), (char *)MemberName);
  2029.  
  2030.   if(!buf) {
  2031.     textWin << "Canceled." << "\n";
  2032.     return;
  2033.   }
  2034.   UString name(buf);
  2035.   
  2036.   // Remove any leading space from the key name entry
  2037.   unsigned offset = name.Find(" ");
  2038.  
  2039.   if(offset == 0) name.DeleteAt(offset, 1);
  2040.   
  2041.   if(name == "") { // Check for a key name valid input
  2042.     comp.DeleteAt(0, comp.length());
  2043.     comp = comp + "Invalid " + MemberName + " input!";
  2044.     frame->textWin->WriteText(comp.c_str());
  2045.     frame->textWin->WriteText("\n");
  2046.     Error->Message(comp.c_str());
  2047.     return;
  2048.   }
  2049.  
  2050.   if(DB->RebuildIndex()) {
  2051.     textWin << "\n";
  2052.     textWin << "The index file needs to be rebuilt." << "\n";
  2053.     return;
  2054.   }
  2055.   
  2056.   Grocery grocery(DB);
  2057.   
  2058.   offset = name.Find(WildCard); // Look for wild card character
  2059.   if(offset == UString::NoMatch) { // No wild cards found
  2060.     grocery.SetName(buf);
  2061.     GrocDBSearch(grocery, item, name, textWin);
  2062.     return;
  2063.   }
  2064.   else 
  2065.     GrocDBSearch(grocery, item, name, textWin, WildCard);
  2066. }
  2067.  
  2068. void GrocDBSearch(Grocery &grocery, GrocDBItem item, UString &str,
  2069.           MyTextWindow &textWin, const char *wildcard)
  2070. {
  2071.   textWin << "Searching for " << str.c_str() << "\n";
  2072.   int offset;
  2073.   offset = ObjectsFound = 0;
  2074.  
  2075.   if(wildcard != 0) {
  2076.     while(1) { // Remove the wild card characters from the string
  2077.       offset = str.Find(wildcard, offset);
  2078.       if (offset == UString::NoMatch) break;
  2079.       str.DeleteAt(offset, strlen(wildcard));
  2080.       offset++;
  2081.     }
  2082.   }
  2083.   
  2084.   // Ensure that the memory buffers and the file data
  2085.   // stay in sync during multiple file access.
  2086.   DB->Index()->TestTree();
  2087.  
  2088.   dllist->Clear();
  2089.   
  2090.   if(wildcard != 0)
  2091.     BtreeSearch(DB->Index(), item, grocery, str, 1);
  2092.   else
  2093.     BtreeSearch(DB->Index(), item, grocery, str);
  2094.  
  2095.   if(ObjectsFound == 0) {
  2096.     textWin << "No matches found." << "\n";
  2097.     return;
  2098.   }
  2099.   else
  2100.     num_objects = ObjectsFound;
  2101.  
  2102.   dllistptr = dllist->GetFront();
  2103.  
  2104.   grand_total = 0;
  2105.   while(!dllist->IsHeader(dllistptr)) {
  2106.     grocery.ReadObject(dllistptr->Data.object_address);
  2107.     grand_total += grocery.GetLineTotal();
  2108.     dllistptr = dllistptr->GetNext();
  2109.   }
  2110.   
  2111.   UString comp;
  2112.   int yn;
  2113.   
  2114.   if(ObjectsFound > 1) { // Found multiple matches
  2115.     textWin << "Found " << ObjectsFound << " matching." << "\n";
  2116.     char intbuf[sbuffer_len];
  2117.     sprintf(intbuf, "%d", ObjectsFound); 
  2118.     comp = comp + "Found " + intbuf + " matching.\nDisplay the objects?";
  2119.     yn = wxMessageBox(comp.c_str(), "Program Message", wxYES_NO|wxCENTRE);
  2120.   }
  2121.   else {
  2122.     textWin << "Found matching entry for: " << str.c_str() << "\n";
  2123.     comp = comp + "Found matching entry for: " + str +  \
  2124.       "\nDisplay the object?";
  2125.     yn = wxMessageBox(comp.c_str(), "Program Message", wxYES_NO|wxCENTRE);
  2126.   }
  2127.  
  2128.   if(yn == wxNO) {
  2129.     dllist->Clear();
  2130.     return;
  2131.   }
  2132.   
  2133.   // Display the first object
  2134.   dllistptr = dllist->GetFront();
  2135.   grocery.ReadObject(dllistptr->Data.object_address);
  2136.   DisplayObject(grocery);
  2137. }
  2138.  
  2139. void ExportToASCII(MyTextWindow &textWin)
  2140. {
  2141.   const char dchar = '\t';   // Text delimiter
  2142.   const char filter = '\t';  // Filter out tabs
  2143.   const char *Fill = "None"; // Fill character string
  2144.   double price, line_total;
  2145.   char purchasing;
  2146.   long quantity;
  2147.   int yn, i;
  2148.   char sbuffer[sbuffer_len];
  2149.   Grocery grocery(DB);
  2150.   
  2151.   textWin.Clear();
  2152.   textWin << "Exporting database to ASCII file delimited by tabs..." << "\n";
  2153.   
  2154.   if(DB->RebuildIndex()) {
  2155.     textWin << "The index file needs to be rebuilt." << "\n";
  2156.     return;
  2157.   }
  2158.  
  2159.   if(displaying_list) {
  2160.     yn = wxMessageBox("Export display list objects?",
  2161.             "Program Message", wxYES_NO|wxCENTRE);
  2162.   }
  2163.   else
  2164.     yn = wxNO;
  2165.  
  2166.   if(yn == wxNO) { LoadIndexKeys(); }
  2167.   if(dllist->IsEmpty()) { LoadIndexKeys(); }
  2168.  
  2169.   char *FileName = wxFileSelector("Export to file:", NULL, NULL, NULL, "*.*");
  2170.  
  2171.   if(FileName) {
  2172. #ifdef wx_msw
  2173.     wxUnix2DosFilename(FileName);
  2174. #endif
  2175.   }
  2176.   else {
  2177.     textWin << "Export canceled." << "\n";
  2178.     return; // No vaild file name
  2179.   }
  2180.   
  2181.   UString sbuf;
  2182.   
  2183.   if(VBDFile::Exists(FileName)) {
  2184.     sbuf = sbuf + "The " + FileName + " file already exists! Overwrite it?";
  2185.     yn = wxMessageBox(sbuf.c_str(), "File Exists", wxYES_NO|wxCENTRE);
  2186.  
  2187.     if(yn == wxNO) {
  2188.     textWin << "Export canceled." << "\n";
  2189.     return;
  2190.     }
  2191.   }
  2192.   
  2193.   ofstream stream(FileName, ios::out); // Open file and truncate it
  2194.   textWin << "Exporting database to: " << FileName << "\n";
  2195.   
  2196.   if(!stream) { // Could not open the stream
  2197.     sbuf.DeleteAt(0, sbuf.length());
  2198.     sbuf = sbuf + "Could not write to: " + FileName;
  2199.     textWin << sbuf.c_str() << "\n";
  2200.     Error->Message(sbuf.c_str());
  2201.     return; 
  2202.   }
  2203.  
  2204.   // Write the item bar to the file first
  2205.   ASPrint(KeyName, stream, strlen(KeyName));
  2206.   stream << dchar;
  2207.  
  2208.   ASPrint(M2Name, stream, strlen(M2Name));
  2209.   stream << dchar;
  2210.   
  2211.   ASPrint(M3Name, stream, strlen(M3Name));
  2212.   stream << dchar;
  2213.     
  2214.   ASPrint(M4Name, stream, strlen(M4Name));
  2215.   stream << dchar;
  2216.   
  2217.   ASPrint(M5Name, stream, strlen(M5Name));
  2218.   stream << dchar;
  2219.  
  2220.   ASPrint(M6Name, stream, strlen(M6Name));
  2221.   stream << dchar;
  2222.  
  2223.   ASPrint(M7Name, stream, strlen(M7Name));
  2224.   stream << asLineFeed;
  2225.   
  2226.   int exports = 0;
  2227.   dllistptr = dllist->GetFront();
  2228.   
  2229.   while(!dllist->IsHeader(dllistptr)) {
  2230.     grocery.ReadObject(dllistptr->Data.object_address);
  2231.  
  2232.     ASPrint(grocery.GetName(), filter, stream, strlen(grocery.GetName()));
  2233.     stream << dchar;
  2234.  
  2235.     if(!*grocery.GetBrand())
  2236.       ASPrint(Fill, stream, strlen(Fill));
  2237.     else
  2238.       ASPrint(grocery.GetBrand(), filter, stream, strlen(grocery.GetBrand()));
  2239.     stream << dchar;
  2240.     
  2241.     if(!*grocery.GetStore())
  2242.       ASPrint(Fill, stream, strlen(Fill));
  2243.     else
  2244.       ASPrint(grocery.GetStore(), filter, stream, strlen(grocery.GetStore()));
  2245.     stream << dchar;
  2246.  
  2247.     price = grocery.GetPrice();
  2248.     sprintf(sbuffer, "%.2f", price);
  2249.     ASPrint(sbuffer, stream, strlen(sbuffer));
  2250.     stream << dchar;
  2251.   
  2252.     quantity = grocery.GetQuantity();
  2253.     for(i = 0; i < sbuffer_len; i++) sbuffer[i] = '\0';
  2254.     sprintf(sbuffer, "%d", quantity);
  2255.     ASPrint(sbuffer, stream, strlen(sbuffer));
  2256.     stream << dchar;
  2257.     
  2258.     purchasing = grocery.GetPurchasing();
  2259.     if(purchasing == 'N' || purchasing == 'n')
  2260.       ASPrint("No", stream, strlen("No"));
  2261.     else
  2262.       ASPrint("Yes", stream, strlen("Yes"));
  2263.     stream << dchar;
  2264.  
  2265.     line_total = grocery.GetLineTotal();
  2266.     for(i = 0; i < sbuffer_len; i++) sbuffer[i] = '\0';
  2267.     sprintf(sbuffer, "%.2f", line_total);
  2268.     ASPrint(sbuffer, stream, strlen(sbuffer));
  2269.     
  2270.     stream << asLineFeed;
  2271.     exports++;
  2272.     dllistptr = dllistptr->GetNext();
  2273.   }
  2274.  
  2275.   textWin << "Exported " << exports << " objects." << "\n";
  2276.   stream.close();
  2277. }
  2278.  
  2279. void ImportFromASCII(MyTextWindow &textWin)
  2280. {
  2281.   if(!AdminRights) {
  2282.     wxMessageBox("You do not have Admin User Privileges\n",
  2283.          "Program Message", wxOK|wxCENTRE);
  2284.     return;
  2285.   }
  2286.   
  2287.   char words[MAXWORDS][MAXWORDLENGTH];
  2288.   int num;
  2289.   const int MaxLine = 512;
  2290.   char LineBuffer[MaxLine];
  2291.   UString sbuf;
  2292.   const char dchar = '\t';  // Text delimiter
  2293.  
  2294.   // wxWindows single choice index box setup
  2295.   int ch = -1;
  2296.   const int CHArray = 4; 
  2297.   
  2298.   char *ch_array[CHArray] = {
  2299.     "Update this entry",
  2300.     "Skip this entry",
  2301.     "Update all entries without prompting",
  2302.     "Quit this import"
  2303.   };
  2304.  
  2305.   enum ICHOICES {
  2306.     UPDATE_ENTRY,
  2307.     UPDATE_SKIP,
  2308.     UPDATE_ALL,
  2309.     QUIT_THIS
  2310.   };
  2311.   
  2312.   textWin.Clear();
  2313.   textWin << "Importing database from ASCII file delimited by tabs..." << "\n";
  2314.  
  2315.   char *FileName = wxFileSelector("Import from file:",
  2316.                   NULL, NULL, NULL, "*.*");
  2317.   if(FileName) {
  2318. #ifdef wx_msw
  2319.     wxUnix2DosFilename(FileName);
  2320. #endif
  2321.   }
  2322.   else {
  2323.     textWin << "Import canceled." << "\n";
  2324.     return; // No vaild file name
  2325.   }
  2326.  
  2327.   ifstream stream(FileName, ios::in|ios::nocreate);
  2328.   textWin << "Importing database from: " << FileName << "\n";
  2329.   
  2330.   if(!stream) { // Could not open the stream
  2331.     textWin << "Could not open file: " << FileName << "\n";
  2332.     return; 
  2333.   }
  2334.  
  2335.   textWin << "Importing..." << "\n";
  2336.  
  2337.   SNode<UString> *sllistptr; // Linked list node pointer
  2338.   SLList<UString> sllist;    // Linked list
  2339.  
  2340.   while(!stream.eof())
  2341.   {
  2342.     // Read in file line by line
  2343.     stream.getline(LineBuffer, MaxLine);
  2344.  
  2345.     // Copy contents of the array to temporary holding buffer
  2346.     sbuf = LineBuffer;
  2347.  
  2348.     // Load file data into singly-linked list
  2349.     sllistptr = sllist.StoreNode(sbuf); 
  2350.  
  2351.     // Clear the string buffer
  2352.     sbuf.DeleteAt(0, sbuf.length());
  2353.     
  2354.     if(!sllistptr) { // Out of memory
  2355.       stream.close();
  2356.       sllist.Clear();
  2357.       return;
  2358.    }
  2359.   }
  2360.   stream.close();
  2361.   
  2362.   Grocery grocery(DB);
  2363.   Grocery grocery_a(DB);
  2364.   Grocery ob(DB);
  2365.  
  2366.   int linecount = 0;
  2367.   int imports = 0;
  2368.   int updates = 0;
  2369.   int updateall = 0;
  2370.   int ObjectItems = 7; // Number of class data members 
  2371.  
  2372.   sllistptr = sllist.GetFront();
  2373.   while(!sllist.IsHeader(sllistptr)) {
  2374.     if(parse(sllistptr->Data.c_str(), words, &num, dchar) == 1) {
  2375.       textWin << "Parse error!" << "\n";
  2376.       break;
  2377.     }
  2378.  
  2379.     linecount++;
  2380.     if(num != ObjectItems && (num != 0 && num != 1)) {
  2381.       textWin << "Error in " << FileName << " import file!" << "\n";
  2382.       if(num > ObjectItems) 
  2383.     textWin << "To many items on line: ";
  2384.       if(num < ObjectItems) 
  2385.     textWin << "Not enough items on line: ";
  2386.       textWin << linecount << "\n";
  2387.       int yn = wxMessageBox("Error in import file! Continue?",
  2388.                 "Program Message", wxYES_NO|wxCENTRE);
  2389.       if(yn == wxNO) {
  2390.       sllist.Clear();
  2391.       return;
  2392.       }
  2393.     }
  2394.     
  2395.     if(num == ObjectItems && *words[0] != 0) {
  2396.       grocery.SetName(words[0]);
  2397.       grocery.SetBrand(words[1]);
  2398.       grocery.SetStore(words[2]);
  2399.       grocery.SetPrice(atof(words[3]));
  2400.       grocery.SetQuantity(atoi(words[4]));
  2401.       char *pur_buf = words[5];
  2402.       if(strcmp(pur_buf, "No") == 0)
  2403.         grocery.SetPurchasing('N');
  2404.       else
  2405.         grocery.SetPurchasing('Y');
  2406.       grocery.SetLineTotal(atof(words[6]));
  2407.       
  2408.       grocery_a.SetName(grocery.GetName());
  2409.       FAU addr = grocery_a.FindObject();
  2410.       
  2411.       if(addr) {
  2412.     if(updateall == 0) {
  2413.       sbuf.DeleteAt(0, sbuf.length());
  2414.           sbuf = sbuf + grocery.GetName() + " entry already exists.\n" + \
  2415.         "Select your choice and click on OK";
  2416.       ch = wxGetSingleChoiceIndex(sbuf.c_str(), "Importing Objects",
  2417.                       CHArray, ch_array, frame);
  2418.     }
  2419.     if(updateall == 1) ch = UPDATE_ALL;
  2420.     switch(ch) {
  2421.       case UPDATE_ALL:
  2422.         updateall = 1;
  2423.         updates++;
  2424.             ob.Copy(grocery_a);
  2425.             if(grocery.FullCompare(ob)) break; // The object has not changed
  2426.         ob.DeleteObject(); 
  2427.             grocery.AddObject(0);
  2428.         sbuf.DeleteAt(0, sbuf.length());
  2429.             sbuf = sbuf + "Updating entry for: " + grocery.GetName();
  2430.         textWin << sbuf.c_str() << "\n";
  2431.         frame->SetStatusText(sbuf.c_str());
  2432.         break;
  2433.       case UPDATE_SKIP:
  2434.         break;
  2435.       case UPDATE_ENTRY:
  2436.         updates++;
  2437.             ob.Copy(grocery_a);
  2438.             if(grocery.FullCompare(ob)) break; // The object has not changed
  2439.         ob.DeleteObject(); 
  2440.             grocery.AddObject(0);
  2441.         sbuf.DeleteAt(0, sbuf.length());
  2442.             sbuf = sbuf + "Updating entry for: " + grocery.GetName();
  2443.         textWin << sbuf.c_str() << "\n";
  2444.         frame->SetStatusText(sbuf.c_str());
  2445.         break;
  2446.       case QUIT_THIS:
  2447.         textWin << "Import cancled." << "\n";
  2448.         textWin << "Imported " << imports << " objects." << "\n";
  2449.         if(updates) {
  2450.           textWin << "Updated " << updates << " objects." << "\n";
  2451.         }
  2452.         sllist.Clear();
  2453.         return;
  2454.       default:
  2455.         break;
  2456.     }
  2457.     if(updateall == 1) {
  2458.       sbuf.DeleteAt(0, sbuf.length());
  2459.           sbuf = sbuf + "Updating entry for: " + grocery.GetName();
  2460.       textWin << sbuf.c_str() << "\n";
  2461.       frame->SetStatusText(sbuf.c_str());
  2462.     }
  2463.     else {
  2464.       // Nothing to do
  2465.     }
  2466.       }
  2467.       else {
  2468.     // Ensure that the template does not get added to the file
  2469.     if(CaseICmp(KeyName, words[0]) != 0) {
  2470.           FAU addr = grocery.AddObject(0); // Write the object to the file
  2471.       imports++;
  2472.       if(!addr) {
  2473.             textWin << "Could not add:" << grocery.GetName()
  2474.             << " to database" << "\n";
  2475.         imports--;
  2476.       }
  2477.     }
  2478.       }
  2479.     }
  2480.     sllistptr = sllistptr->GetNext();
  2481.   }
  2482.  
  2483.   textWin << "Imported " << imports << " objects." << "\n";
  2484.   if(updates) {
  2485.     textWin << "Updated " << updates << " objects." << "\n";
  2486.   }
  2487.  
  2488.   sllist.Clear();
  2489. }
  2490.  
  2491. void BackUp(MyTextWindow &textWin)
  2492. {
  2493.   textWin.Clear();
  2494.   textWin << "Backing up the database to another file..." << "\n";
  2495.  
  2496.   char *FileName = wxFileSelector("Backup to file:",
  2497.                   NULL, NULL, NULL, "*.*");
  2498.   if(FileName) {
  2499. #ifdef wx_msw
  2500.     wxUnix2DosFilename(FileName);
  2501. #endif
  2502.   }
  2503.   else {
  2504.     textWin << "Backup canceled." << "\n";
  2505.     return; // No vaild file name
  2506.   }
  2507.   
  2508.   UString sbuf;
  2509.  
  2510.   if(VBDFile::Exists(FileName)) {
  2511.     sbuf = sbuf + "The " + FileName + " file already exists!\nOverwrite it?";
  2512.     int yn = wxMessageBox(sbuf.c_str(), "File Exists", wxYES_NO|wxCENTRE);
  2513.  
  2514.     if(yn == wxNO) {
  2515.     textWin << "Export canceled." << "\n";
  2516.     return;
  2517.     }
  2518.  
  2519.     if(!wxRemoveFile(FileName)) {
  2520.       sbuf.DeleteAt(0, sbuf.length());
  2521.       sbuf = sbuf + "Could not write to: " + FileName;
  2522.       textWin << sbuf.c_str() << "\n";
  2523.       Error->Message(sbuf.c_str());
  2524.       return; 
  2525.     }
  2526.   }
  2527.  
  2528.   POD newdb(FileName, FileName);
  2529.   int items = 0;
  2530.   Grocery grocery(&newdb);
  2531.   Grocery grocery_old(DB);
  2532.   
  2533.   if(DB->RebuildIndex()) {
  2534.     textWin << "\n";
  2535.     textWin << "The index file needs to be rebuilt." << "\n";
  2536.     return;
  2537.   }
  2538.  
  2539.   CachePointer nxt(*DB->Index()->GetCache());
  2540.   BtreeWalkerb tw(DB->Index(), btINORDER);
  2541.   nxt = DB->Index()->GetRoot();
  2542.  
  2543.   while((__LWORD__)nxt != 0) {
  2544.     nxt = tw.Next();
  2545.     if((__LWORD__)nxt) {
  2546.       for(int i = 0; i < nxt->cnt; i++) {
  2547.     grocery_old.ReadObject(nxt->entry[i].object_address);
  2548.     grocery.Copy(grocery_old);
  2549.     grocery.AddObject(0);
  2550.     items++;
  2551.       }
  2552.     }
  2553.   }
  2554.   textWin << "Backed up " << items << " objects to " << FileName << "\n";
  2555. }
  2556.  
  2557. void Merge(MyTextWindow &textWin)
  2558. {
  2559.   if(!AdminRights) {
  2560.     wxMessageBox("You do not have Admin User Privileges\n",
  2561.          "Program Message", wxOK|wxCENTRE);
  2562.     return;
  2563.   }
  2564.   
  2565.   // wxWindows single choice index box setup
  2566.   int ch = -1;
  2567.   const int CHArray = 4; 
  2568.   
  2569.   char *ch_array[CHArray] = {
  2570.     "Update this entry",
  2571.     "Skip this entry",
  2572.     "Update all entries without prompting",
  2573.     "Quit this merge"
  2574.   };
  2575.  
  2576.   enum ICHOICES {
  2577.     UPDATE_ENTRY,
  2578.     UPDATE_SKIP,
  2579.     UPDATE_ALL,
  2580.     QUIT_THIS
  2581.   };
  2582.   
  2583.   textWin.Clear();
  2584.   textWin << "Merging the contents of another database..." << "\n";
  2585.  
  2586.   char *FileName = wxFileSelector("Merge from file:", NULL, NULL, NULL, "*.*");
  2587.   if(FileName) {
  2588. #ifdef wx_msw
  2589.     wxUnix2DosFilename(FileName);
  2590. #endif
  2591.   }
  2592.   else {
  2593.     textWin << "Merge canceled." << "\n";
  2594.     return; // No vaild file name
  2595.   }
  2596.   
  2597.   POD newdb(FileName, FileName);
  2598.   Grocery grocery(&newdb);
  2599.   Grocery grocery_a(DB);
  2600.   Grocery ob(DB);
  2601.   FAU existing;
  2602.   FAU addr;
  2603.   UString sbuf;
  2604.  
  2605.   int imports = 0;
  2606.   int updates = 0;
  2607.   int updateall = 0;
  2608.   
  2609.   FAU oa;          // Object Address
  2610.   VBlockHeader vb;     // Variable Block Header
  2611.   ObjectHeader oh; // Object Header
  2612.  
  2613.   FAU vbdfileEOF = newdb.OpenDatabase()->GetEOF();
  2614.   
  2615.   addr = 0;
  2616.   addr = newdb.OpenDatabase()->FindFirstVB(addr); // Search the entire file
  2617.  
  2618.   if(addr == 0) {
  2619.     textWin << "No variable blocks found in file: " << FileName << "\n";
  2620.     return;
  2621.   }
  2622.  
  2623.   textWin << "Merging..." << "\n";
  2624.  
  2625.   while(1) { 
  2626.     if(addr >= vbdfileEOF) break;
  2627.     newdb.OpenDatabase()->Read(&vb, sizeof(VBlockHeader), addr);
  2628.     if(vb.CkWord == CheckWord) {
  2629.       if((__SBYTE__)vb.VBStatus == NormalVB) {
  2630.     oa = addr + sizeof(VBlockHeader);
  2631.     newdb.OpenDatabase()->Read(&oh, sizeof(ObjectHeader), oa);
  2632.     if(oh.ClassID == grocery.GetClassID()) { 
  2633.       grocery.ReadObject(oa);
  2634.       grocery_a.SetName(grocery.GetName());
  2635.       existing = grocery_a.FindObject();
  2636.       if(existing) {
  2637.         if(updateall == 0) {
  2638.           sbuf.DeleteAt(0, sbuf.length());
  2639.           sbuf = sbuf +  grocery_a.GetName() + \
  2640.         " entry already exists.\n" + \
  2641.         "Select your choice and click on OK"; 
  2642.           ch = wxGetSingleChoiceIndex(sbuf.c_str(), "Importing Objects",
  2643.                       CHArray, ch_array, frame);
  2644.         }
  2645.         if(updateall == 1) ch = UPDATE_ALL;
  2646.         switch(ch) {
  2647.           case UPDATE_ALL:
  2648.         updateall = 1;
  2649.         updates++;
  2650.         ob.Copy(grocery);
  2651.         if(grocery.FullCompare(ob)) break; // Object has not changed
  2652.         ob.DeleteObject(); 
  2653.         ob.Copy(grocery);
  2654.         ob.AddObject(0);
  2655.         sbuf.DeleteAt(0, sbuf.length());
  2656.         sbuf = sbuf  + "Updating entry for: " + grocery.GetName();
  2657.         textWin << sbuf.c_str() << "\n";
  2658.         frame->SetStatusText(sbuf.c_str());
  2659.         break;
  2660.           case UPDATE_SKIP:
  2661.         break;
  2662.           case UPDATE_ENTRY:
  2663.         updates++;
  2664.         ob.Copy(grocery);
  2665.         if(grocery.FullCompare(ob)) break; // Object has not changed
  2666.         ob.DeleteObject(); 
  2667.         ob.Copy(grocery);
  2668.         ob.AddObject(0);
  2669.         sbuf.DeleteAt(0, sbuf.length());
  2670.         sbuf = sbuf + "Updating entry for: " + grocery.GetName();
  2671.         textWin << sbuf.c_str() << "\n";
  2672.         frame->SetStatusText(sbuf.c_str());
  2673.         break;
  2674.           case QUIT_THIS:
  2675.         textWin << "Merge cancled." << "\n";
  2676.         textWin << "Imported " << imports << " objects." << "\n";
  2677.         if(updates) {
  2678.           textWin << "Updated " << updates << " objects." << "\n";
  2679.         }
  2680.         return;
  2681.           default:
  2682.         break;
  2683.         }
  2684.         if(updateall == 1) {
  2685.           sbuf.DeleteAt(0, sbuf.length());
  2686.           sbuf = sbuf + "Updating entry for: " + grocery.GetName();
  2687.           textWin << sbuf.c_str() << "\n";
  2688.           frame->SetStatusText(sbuf.c_str());
  2689.         }
  2690.         else {
  2691.           // Nothing to do
  2692.         }
  2693.       }
  2694.       else {
  2695.         grocery_a.Copy(grocery);
  2696.         FAU rvaddr = grocery_a.AddObject(0); // Write object to the file
  2697.         imports++;
  2698.         if(!rvaddr) {
  2699.           textWin << "Could not add:" << grocery.GetName()
  2700.               << " to database" << "\n";
  2701.           imports--;
  2702.         }
  2703.         
  2704.       }
  2705.     }
  2706.     
  2707.       }
  2708.       addr = addr + vb.Length; // Goto the next variable block
  2709.     }
  2710.     else {
  2711.       addr = newdb.OpenDatabase()->VBSearch(addr); 
  2712.       if(!addr) break;
  2713.     }
  2714.   }
  2715.   
  2716.   textWin << "Imported " << imports << " objects." << "\n";
  2717.   if(updates) {
  2718.     textWin << "Updated " << updates << " objects." << "\n";
  2719.   }
  2720. }
  2721.  
  2722. void CreateTemplate(MyTextWindow &textWin)
  2723. {
  2724.   const char dchar = '\t';   // Text delimiter
  2725.  
  2726.   textWin.Clear();
  2727.   textWin << "Creating template file delimited by tabs..." << "\n";
  2728.  
  2729.  
  2730.   char *FileName = wxFileSelector("Template file to create:",
  2731.                   NULL, NULL, NULL, "*.*");
  2732.   if(FileName) {
  2733. #ifdef wx_msw
  2734.     wxUnix2DosFilename(FileName);
  2735. #endif
  2736.   }
  2737.   else {
  2738.     textWin << "Creating template canceled." << "\n";
  2739.     return; // No vaild file name
  2740.   }
  2741.   
  2742.   UString sbuf;
  2743.   
  2744.   if(VBDFile::Exists(FileName)) {
  2745.     sbuf = sbuf + "The " + FileName + " file already exists!\nOverwrite it?";
  2746.     int yn = wxMessageBox(sbuf.c_str(), "File Exists", wxYES_NO|wxCENTRE);
  2747.  
  2748.     if(yn == wxNO) {
  2749.     textWin << "Creating template canceled." << "\n";
  2750.     return;
  2751.     }
  2752.   }
  2753.   
  2754.   ofstream stream(FileName, ios::out); // Open file and truncate it
  2755.   textWin << "Creating template file: " << FileName << "\n";
  2756.  
  2757.   if(!stream) { // Could not open the stream
  2758.     sbuf.DeleteAt(0, sbuf.length());
  2759.     sbuf = sbuf  + "Could not write to: " + FileName;
  2760.     textWin << sbuf.c_str() << "\n";
  2761.     Error->Message(sbuf.c_str());
  2762.     return; 
  2763.   }
  2764.  
  2765.   ASPrint(KeyName, stream, strlen(KeyName));
  2766.   stream << dchar;
  2767.   
  2768.   ASPrint(M2Name, stream, strlen(M2Name));
  2769.   stream << dchar;
  2770.  
  2771.   ASPrint(M3Name, stream, strlen(M3Name));
  2772.   stream << dchar;
  2773.  
  2774.   ASPrint(M4Name, stream, strlen(M4Name));
  2775.   stream << dchar;
  2776.  
  2777.   ASPrint(M5Name, stream, strlen(M5Name));
  2778.   stream << dchar;
  2779.  
  2780.   ASPrint(M6Name, stream, strlen(M6Name));
  2781.   stream << dchar;
  2782.  
  2783.   ASPrint(M7Name, stream, strlen(M7Name));
  2784.   stream << asLineFeed;
  2785.   
  2786.   textWin << "Finished." << "\n";
  2787.   stream.close();
  2788. }
  2789.  
  2790. void ASCIIPrintAll(MyTextWindow &textWin)
  2791. {
  2792.   textWin.Clear();
  2793.   textWin << "Printing database to ASCII file..." << "\n";
  2794.   int yn;
  2795.   
  2796.   if(DB->RebuildIndex()) {
  2797.     textWin << "The index file needs to be rebuilt." << "\n";
  2798.     return;
  2799.   }
  2800.  
  2801.   if(displaying_list) {
  2802.     yn = wxMessageBox("Print display list objects?",
  2803.               "Program Message", wxYES_NO|wxCENTRE);
  2804.   }
  2805.   else
  2806.     yn = wxNO;
  2807.  
  2808.   if(yn == wxNO) LoadIndexKeys(as_print_all);
  2809.   if(dllist->IsEmpty()) LoadIndexKeys(as_print_all);
  2810.   if(yn == wxYES && as_print_all == 0) ReOrderDisplayList();
  2811.   
  2812.   char *FileName = wxFileSelector("Print database to file:",
  2813.                   NULL, NULL, NULL, "*.*");
  2814.   if(FileName) {
  2815. #ifdef wx_msw
  2816.     wxUnix2DosFilename(FileName);
  2817. #endif
  2818.   }
  2819.   else {
  2820.     textWin << "ASCII print canceled." << "\n";
  2821.     return; // No vaild file name
  2822.   }
  2823.   
  2824.   UString sbuf;
  2825.   
  2826.   if(VBDFile::Exists(FileName)) {
  2827.     sbuf = sbuf + "The " + FileName + " file already exists!\nOverwrite it?";
  2828.     yn = wxMessageBox(sbuf.c_str(), "File Exists", wxYES_NO|wxCENTRE);
  2829.  
  2830.     if(yn == wxNO) {
  2831.       textWin << "ASCII print canceled." << "\n";
  2832.       return;
  2833.     }
  2834.   }
  2835.   
  2836.   ofstream stream(FileName, ios::out); // Open file and truncate it
  2837.   textWin << "Printing to: " << FileName << "\n";
  2838.   
  2839.   if(!stream) { // Could not open the stream
  2840.     sbuf.DeleteAt(0, sbuf.length());
  2841.     sbuf = sbuf + "Could not write to: " + FileName;
  2842.     textWin << sbuf.c_str() << "\n";
  2843.     Error->Message(sbuf.c_str());
  2844.     return; 
  2845.   }
  2846.  
  2847.   textWin << "Printing..." << "\n";
  2848.   Grocery grocery(DB);
  2849.   PrintItemBar(stream);
  2850.   dllistptr = dllist->GetFront();
  2851.  
  2852.   while(!dllist->IsHeader(dllistptr)) {
  2853.     grocery.ReadObject(dllistptr->Data.object_address);
  2854.     PrintLineByLine(grocery, stream);
  2855.     dllistptr = dllistptr->GetNext();
  2856.   }
  2857.   
  2858.   textWin << "Finished." << "\n";
  2859.   stream.close();
  2860. }
  2861.  
  2862. void PrintItemBar(ofstream &stream)
  2863. {
  2864.   int i = 0;
  2865.   ASPrint(KeyName, stream, StringOffset+1);
  2866.   ASPrint(M2Name, stream, StringOffset+1);
  2867.   ASPrint(M3Name, stream, StringOffset+1);
  2868.   ASPrint(M4Name, stream, StringOffset+1);
  2869.   ASPrint(M5Name, stream, StringOffset);
  2870.   ASPrint(M7Name, stream, StringOffset+1);
  2871.   stream << asLineFeed;
  2872.   i = 0;
  2873.   while (i++ < PrintColsSpec-1) stream << '=';
  2874.   stream << asLineFeed;
  2875. }
  2876.  
  2877. void PrintLineByLine(Grocery &grocery, ofstream &stream)
  2878. {
  2879.   int i;
  2880.   double price, line_total;
  2881.   long quantity;
  2882.   char sbuffer[sbuffer_len];
  2883.   
  2884.   ASPrint(grocery.GetName(), stream, StringOffset+1);
  2885.   ASPrint(grocery.GetBrand(), stream, StringOffset+1);
  2886.   ASPrint(grocery.GetStore(), stream, StringOffset+1);
  2887.  
  2888.   price = grocery.GetPrice();
  2889.   sprintf(sbuffer, "%.2f", price);
  2890.   ASPrint(sbuffer, stream, StringOffset+1);
  2891.  
  2892.   quantity = grocery.GetQuantity();
  2893.   for(i = 0; i < sbuffer_len; i++) sbuffer[i] = '\0';
  2894.   sprintf(sbuffer, "%d", quantity);
  2895.   ASPrint(sbuffer, stream, StringOffset+1);
  2896.  
  2897.   line_total = grocery.GetLineTotal();
  2898.   for(i = 0; i < sbuffer_len; i++) sbuffer[i] = '\0';
  2899.   sprintf(sbuffer, "%.2f", line_total);
  2900.   ASPrint(sbuffer, stream, StringOffset+1);
  2901.   stream << asLineFeed;
  2902.   i = 0;
  2903.   while (i++ < PrintColsSpec-1) stream << '-';
  2904.   stream << asLineFeed;
  2905. }
  2906.  
  2907. void CompareIndexFile(MyTextWindow &textWin)
  2908. {
  2909.   textWin.Clear();
  2910.   textWin << "Comparing the index file to the data file..." << "\n";
  2911.   
  2912.   Grocery grocery(DB);
  2913.   int rv = grocery.CompareIndex();
  2914.   if(!rv) {
  2915.     textWin << "The index file does not match the data file!" << "\n";
  2916.     textWin << "The index file needs to be rebuilt." << "\n";
  2917.     return;
  2918.   }
  2919.  
  2920.   textWin << "The index file checks good." << "\n";
  2921. }
  2922.  
  2923. void RebuildIndexFile(MyTextWindow &textWin)
  2924. {
  2925.   textWin.Clear();
  2926.   textWin << "Rebuilding the index file..." << "\n";
  2927.   UString sbuf;
  2928.   
  2929.   char *FileName = wxFileSelector("Enter name for new index file:",
  2930.                   NULL, NULL, NULL, "*.*");
  2931.   if(FileName) {
  2932. #ifdef wx_msw
  2933.     wxUnix2DosFilename(FileName);
  2934. #endif
  2935.   }
  2936.   else {
  2937.     textWin << "Rebuild canceled." << "\n";
  2938.     return; // No vaild file name
  2939.   }
  2940.  
  2941.   if(VBDFile::Exists(FileName)) {
  2942.     sbuf = sbuf + "The " + FileName + " file already exists!\nOverwrite it?";
  2943.     int yn = wxMessageBox(sbuf.c_str(), "File Exists", wxYES_NO|wxCENTRE);
  2944.  
  2945.     if(yn == wxNO) {
  2946.     textWin << "Rebuild canceled." << "\n";
  2947.     return;
  2948.     }
  2949.  
  2950.     if(!wxRemoveFile(FileName)) {
  2951.       sbuf.DeleteAt(0, sbuf.length());
  2952.       sbuf = sbuf + "Could not write to: " + FileName;
  2953.       textWin << sbuf.c_str() << "\n";
  2954.       Error->Message(sbuf.c_str());
  2955.       return; 
  2956.     }
  2957.   }
  2958.   
  2959.   Grocery grocery(DB);
  2960.   int rv = grocery.RebuildIndexFile(FileName);
  2961.   
  2962.   if(!rv) {
  2963.     textWin << "The index file was not rebuilt!" << "\n";
  2964.     return;
  2965.   }
  2966.  
  2967.   textWin << "The index file was rebuilt." << "\n";
  2968.   textWin << "A new index file named:\n"
  2969.       << FileName << " was created." << "\n";
  2970. }
  2971.  
  2972. void ViewTotals(MyTextWindow &textWin)
  2973. {
  2974.   textWin.Clear();
  2975.   if(view_all == 0)
  2976.     textWin << "Viewing total cost of objects selected for purchase." << "\n";
  2977.   else
  2978.     textWin << "Viewing total cost of all objects." << "\n";
  2979.  
  2980.   if(view_all == 0) {
  2981.     LoadIndexKeys(0);
  2982.   }
  2983.   else {
  2984.     LoadIndexKeys(1);
  2985.   }
  2986.  
  2987.   int i;
  2988.   char sbuffer[sbuffer_len];
  2989.   sprintf(sbuffer, "TOTAL BEFORE TAX = $%.2f", grand_total);
  2990.   textWin << "\n";
  2991.   textWin << sbuffer << "\n";
  2992.  
  2993.   if(sales_tax <= 0) {
  2994.     textWin << "\n";
  2995.     textWin << "No sales tax value set in config file." << "\n";
  2996.     textWin << "\n";
  2997.     return; 
  2998.   }
  2999.  
  3000.   double tax_percent = sales_tax / 100;
  3001.   double tax = tax_percent * grand_total;
  3002.   double tax_total = grand_total;
  3003.   
  3004.   for(i = 0; i < sbuffer_len; i++) sbuffer[i] = '\0';
  3005.   sprintf(sbuffer, "SALES TAX = $%.2f", tax);
  3006.   textWin << "\n";
  3007.   textWin << sbuffer << "\n";
  3008.   
  3009.   for(i = 0; i < sbuffer_len; i++) sbuffer[i] = '\0';
  3010.   tax_total += tax;
  3011.   sprintf(sbuffer, "GRAND TOTAL = $%.2f", tax_total);
  3012.   textWin << "\n";
  3013.   textWin << sbuffer << "\n";
  3014.   textWin << "\n";
  3015. }
  3016.  
  3017. void SetPurchasing(MyTextWindow &textWin, char purchasing)
  3018. {
  3019.   if(!AdminRights) {
  3020.       wxMessageBox("You do not have Admin User Privileges\n",
  3021.            "Program Message", wxOK|wxCENTRE);
  3022.     return;
  3023.   }
  3024.  
  3025.   textWin.Clear();
  3026.   if(purchasing == 'Y' || purchasing == 'y')
  3027.     textWin << "Purchasing all objects in the database." << "\n";
  3028.   else
  3029.     textWin << "Setting all objects for purchase to no." << "\n";
  3030.  
  3031.   Grocery grocery(DB);
  3032.   
  3033.   CachePointer nxt(*DB->Index()->GetCache());
  3034.   BtreeWalkerb tw(DB->Index(), btLVLORDER);
  3035.   nxt = DB->Index()->GetRoot();
  3036.  
  3037.   while((__LWORD__)nxt != 0) {
  3038.     nxt = tw.Next();
  3039.     if((__LWORD__)nxt) {
  3040.       for(int i = 0; i < nxt->cnt; i++) {
  3041.     grocery.ReadObject(nxt->entry[i].object_address);
  3042.     grocery.SetPurchasing(purchasing);
  3043.     grocery.SaveChanges();
  3044.       }
  3045.     }
  3046.   }
  3047. }
  3048.  
  3049. int PrintPSItemBar(ofstream &stream, PostScriptDrv &psdrv,
  3050.             int x_offset, int char_offset, int cell_len)
  3051. {
  3052.     psdrv.PrintLine((char *)KeyName, cell_len, stream);
  3053.     x_offset += char_offset;
  3054.  
  3055.     psdrv.MoveTo(stream, x_offset, psdrv.row);
  3056.     psdrv.PrintLine((char *)M2Name, cell_len, stream);
  3057.     x_offset += char_offset;
  3058.  
  3059.     psdrv.MoveTo(stream, x_offset, psdrv.row);
  3060.     psdrv.PrintLine((char *)M3Name, cell_len, stream);
  3061.     x_offset += char_offset;
  3062.  
  3063.     psdrv.MoveTo(stream, x_offset, psdrv.row);
  3064.     psdrv.PrintLine((char *)M4Name, cell_len, stream);
  3065.     x_offset += char_offset;
  3066.  
  3067.     psdrv.MoveTo(stream, x_offset, psdrv.row);
  3068.     psdrv.PrintLine((char *)M5Name, cell_len, stream);
  3069.     x_offset += char_offset;
  3070.  
  3071.     psdrv.MoveTo(stream, x_offset, psdrv.row);
  3072.     psdrv.PrintLine((char *)M7Name, cell_len, stream);
  3073.     x_offset += char_offset;
  3074.  
  3075.   return x_offset;
  3076. }
  3077.  
  3078. void PostScriptPrint(MyTextWindow &textWin)
  3079. {
  3080.   textWin.Clear();
  3081.   textWin << "Printing database to PostScript file..." << "\n";
  3082.   int yn, i;
  3083.   
  3084.   if(DB->RebuildIndex()) {
  3085.     textWin << "The index file needs to be rebuilt." << "\n";
  3086.     return;
  3087.   }
  3088.  
  3089.   // Setup the default values for user configurable PostScript parameters
  3090.   int cell_len = 19;    
  3091.   double font_size = 7; 
  3092.   int orientation = 0;
  3093.   const int DocNameLen = 255;
  3094.   char psDocName[DocNameLen];
  3095.   for(i = 0; i < DocNameLen; i++) psDocName[i] = 0;
  3096.   strcpy(psDocName, ProgramName);
  3097.  
  3098.   PostScriptDrv::PSPaperSizes paper_code = PostScriptDrv::LETTER_SIZE;
  3099.   PostScriptDrv::PSFonts item_font = PostScriptDrv::COURIER_BOLD_OBLIQUE;
  3100.   PostScriptDrv::PSFonts cell_font = PostScriptDrv::COURIER;
  3101.  
  3102.   // Load the PostScript configuration from the config file
  3103.   char *CurrentCfgFile;
  3104.   char *CfgFile;
  3105.   Config *CfgData = new Config;
  3106.   int int_val = 0;
  3107.   double dfp_val = 0;
  3108.   char *str_val = 0;
  3109.  
  3110.   // Look for CfgFile name in environment
  3111.   if((CurrentCfgFile = getenv(EnvSetting)) == 0)
  3112.     CfgFile = (char *)DefaultCfgFile;
  3113.   else
  3114.     CfgFile = CurrentCfgFile;
  3115.  
  3116.   int FileStatus = CfgData->Load((char *)CfgFile);
  3117.   if(FileStatus) { // Found a valid config file
  3118. // *********************************************************** //
  3119. // Add all PostScript config file entries here
  3120. // *********************************************************** //
  3121.     int_val = CfgData->GetIntValue("CellLength");
  3122.     if(int_val > 0) cell_len = int_val;
  3123.  
  3124.     dfp_val = CfgData->GetDFPValue("FontSize");
  3125.     if(dfp_val > 0) font_size = dfp_val;
  3126.  
  3127.     str_val = CfgData->GetStrValue("Orientation");
  3128.     if(str_val != 0) {
  3129.       if(strcmp(str_val, "PORTRAIT") == 0) orientation = 0;
  3130.       str_val = 0;
  3131.     }
  3132.     
  3133.     str_val = CfgData->GetStrValue("PaperSize");
  3134.     if(str_val != 0) {
  3135.       if(strcmp(str_val, "LETTER") == 0)
  3136.     paper_code = PostScriptDrv::LETTER_SIZE;
  3137.       if(strcmp(str_val, "LEGAL") == 0)
  3138.     paper_code = PostScriptDrv::LEGAL_SIZE;
  3139.       if(strcmp(str_val, "TABLOID") == 0)
  3140.     paper_code = PostScriptDrv::TABLOID_SIZE;
  3141.       if(strcmp(str_val, "A3") == 0) paper_code = PostScriptDrv::A3_SIZE;
  3142.       if(strcmp(str_val, "A4") == 0) paper_code = PostScriptDrv::A4_SIZE;
  3143.       str_val = 0;
  3144.     }
  3145.  
  3146.     str_val = CfgData->GetStrValue("ItemBarFont");
  3147.     if(str_val != 0) {
  3148.       if(strcmp(str_val, "COURIER") == 0)
  3149.     item_font = PostScriptDrv::COURIER;
  3150.       if(strcmp(str_val, "COURIER_BOLD") == 0)
  3151.     item_font = PostScriptDrv::COURIER_BOLD;
  3152.       if(strcmp(str_val, "COURIER_OBLIQUE") == 0)
  3153.     item_font = PostScriptDrv::COURIER_OBLIQUE;
  3154.       if(strcmp(str_val, "COURIER_BOLD_OBLIQUE") == 0)
  3155.     item_font = PostScriptDrv::COURIER_BOLD_OBLIQUE;
  3156.       str_val = 0;
  3157.     }
  3158.     
  3159.     str_val = CfgData->GetStrValue("CellFont");
  3160.     if(str_val != 0) {
  3161.       if(strcmp(str_val, "COURIER") == 0)
  3162.     cell_font = PostScriptDrv::COURIER;
  3163.       if(strcmp(str_val, "COURIER_BOLD") == 0)
  3164.     cell_font = PostScriptDrv::COURIER_BOLD;
  3165.       if(strcmp(str_val, "COURIER_OBLIQUE") == 0)
  3166.     cell_font = PostScriptDrv::COURIER_OBLIQUE;
  3167.       if(strcmp(str_val, "COURIER_BOLD_OBLIQUE") == 0)
  3168.     cell_font = PostScriptDrv::COURIER_BOLD_OBLIQUE;
  3169.     }
  3170.  
  3171.     str_val = CfgData->GetStrValue("psDocumentName");
  3172.     if(str_val != 0) {
  3173.       for(i = 0; i < DocNameLen; i++) psDocName[i] = 0;
  3174.       strcpy(psDocName, str_val);
  3175.     }
  3176.  
  3177. // *********************************************************** //    
  3178.   }
  3179.   CfgData->UnLoad(); // Unload the Config file from memory
  3180.  
  3181.   if(displaying_list) {
  3182.     yn = wxMessageBox("Print display list objects?",
  3183.               "Program Message", wxYES_NO|wxCENTRE);
  3184.   }
  3185.   else
  3186.     yn = wxNO;
  3187.  
  3188.   if(yn == wxNO) LoadIndexKeys(ps_print_all);
  3189.   if(dllist->IsEmpty()) LoadIndexKeys(ps_print_all);
  3190.   if(yn == wxYES && ps_print_all == 0) ReOrderDisplayList();
  3191.   
  3192.   char *FileName = wxFileSelector("Print database to PostScript file:",
  3193.                   NULL, NULL, NULL, "*.*");
  3194.   if(FileName) {
  3195. #ifdef wx_msw
  3196.     wxUnix2DosFilename(FileName);
  3197. #endif
  3198.   }
  3199.   else {
  3200.     textWin << "PostScript print canceled." << "\n";
  3201.     return; // No vaild file name
  3202.   }
  3203.   
  3204.   UString sbuf;
  3205.   
  3206.   if(VBDFile::Exists(FileName)) {
  3207.     sbuf = sbuf + "The " + FileName + " file already exists!\nOverwrite it?";
  3208.     int yn = wxMessageBox(sbuf.c_str(), "File Exists", wxYES_NO|wxCENTRE);
  3209.  
  3210.     if(yn == wxNO) {
  3211.       textWin << "PostScript print canceled." << "\n";
  3212.       return;
  3213.     }
  3214.   }
  3215.   
  3216.   ofstream stream(FileName, ios::out); // Open file and truncate it
  3217.   textWin << "Printing to: " << FileName << "\n";
  3218.   
  3219.   if(!stream) { // Could not open the stream
  3220.     sbuf.DeleteAt(0, sbuf.length());
  3221.     sbuf = sbuf + "Could not write to: " + FileName;
  3222.     textWin << sbuf.c_str() << "\n";
  3223.     Error->Message(sbuf.c_str());
  3224.     return; 
  3225.   }
  3226.  
  3227.   textWin << "Printing..." << "\n";
  3228.  
  3229.   PostScriptDrv psdrv;
  3230.   psdrv.Copies(1);
  3231.   
  3232.   // Setup the PostScript driver
  3233.   psdrv.SetPaperSize(paper_code);
  3234.   psdrv.SetFont(cell_font, font_size);
  3235.   psdrv.UseHeader();
  3236.   if(orientation == 1) psdrv.LandScapeMode();
  3237.   psdrv.SetDocumentName(psDocName);
  3238.   char time_buf[255]; // Buffer used to hold time/date string
  3239.   GetSystemTime(time_buf);
  3240.   psdrv.SetDateString(time_buf);
  3241.   psdrv.DocumentSetup();
  3242.   psdrv.Prologue(stream);
  3243.   psdrv.MediaSetup(stream);
  3244.   Grocery grocery(DB);
  3245.   double price, line_total;
  3246.   long quantity;
  3247.   char sbuffer[sbuffer_len];
  3248.  
  3249.   int char_offset = int((cell_len + 1) * psdrv.CharWidth());
  3250.   int x_offset;
  3251.   if(orientation == 0)
  3252.     x_offset = int(HEADER_OFFSET * PIXELS_PER_INCH);
  3253.   else
  3254.     x_offset = PRINTABLE_OFFSET_X;
  3255.  
  3256.   int lines = 4;
  3257.   psdrv.StartPage(psdrv.page_count + 1, stream);
  3258.   psdrv.row = psdrv.StartY();
  3259.   psdrv.MoveTo(stream, psdrv.StartX(), psdrv.row);
  3260.  
  3261.   psdrv.ChangeFont(stream, item_font, font_size);
  3262.   x_offset = PrintPSItemBar(stream, psdrv, x_offset, char_offset, cell_len);
  3263.   psdrv.ChangeFont(stream, cell_font, font_size);
  3264.   
  3265.   int line_points;
  3266.   if(orientation == 0)
  3267.     line_points = int(x_offset - (HEADER_OFFSET * PIXELS_PER_INCH));
  3268.   else
  3269.     line_points = x_offset - PRINTABLE_OFFSET_X;
  3270.  
  3271.   psdrv.row -= (int)psdrv.FontSize();
  3272.   lines++;
  3273.   psdrv.drawThickLine(stream, line_points, psdrv.StartX(), psdrv.row);
  3274.   psdrv.row -= THICK_LINE_WIDTH + psdrv.FontSize();
  3275.   lines ++;
  3276.   
  3277.   dllistptr = dllist->GetFront();  
  3278.   while(!dllist->IsHeader(dllistptr)) {
  3279.     grocery.ReadObject(dllistptr->Data.object_address);
  3280.  
  3281.     if(orientation == 0)
  3282.       x_offset = int(HEADER_OFFSET * PIXELS_PER_INCH);
  3283.     else
  3284.       x_offset = PRINTABLE_OFFSET_X;
  3285.  
  3286.     psdrv.MoveTo(stream, x_offset, psdrv.row);
  3287.     psdrv.PrintLine(grocery.GetName(), cell_len, stream);
  3288.     x_offset += char_offset;
  3289.  
  3290.     psdrv.MoveTo(stream, x_offset, psdrv.row);
  3291.     psdrv.PrintLine(grocery.GetBrand(), cell_len, stream);
  3292.     x_offset += char_offset;
  3293.     
  3294.     psdrv.MoveTo(stream, x_offset, psdrv.row);
  3295.     psdrv.PrintLine(grocery.GetStore(), cell_len, stream);
  3296.     x_offset += char_offset;
  3297.     
  3298.     price = grocery.GetPrice();
  3299.     sprintf(sbuffer, "%.2f", price);
  3300.     psdrv.MoveTo(stream, x_offset, psdrv.row);
  3301.     psdrv.PrintLine(sbuffer, cell_len, stream);
  3302.     x_offset += char_offset;
  3303.      
  3304.     quantity = grocery.GetQuantity();
  3305.     for(i = 0; i < sbuffer_len; i++) sbuffer[i] = '\0';
  3306.     sprintf(sbuffer, "%d", quantity);
  3307.     psdrv.MoveTo(stream, x_offset, psdrv.row);
  3308.     psdrv.PrintLine(sbuffer, cell_len, stream);
  3309.     x_offset += char_offset;
  3310.     
  3311.     line_total = grocery.GetLineTotal();
  3312.     for(i = 0; i < sbuffer_len; i++) sbuffer[i] = '\0';
  3313.     sprintf(sbuffer, "%.2f", line_total);
  3314.     psdrv.MoveTo(stream, x_offset, psdrv.row);
  3315.     psdrv.PrintLine(sbuffer, cell_len, stream);
  3316.     x_offset += char_offset;
  3317.  
  3318.     psdrv.row -= psdrv.FontSize();
  3319.     lines++;
  3320.     if(orientation == 0)
  3321.       line_points = int(x_offset - (HEADER_OFFSET * PIXELS_PER_INCH));
  3322.     else
  3323.       line_points = x_offset - PRINTABLE_OFFSET_X;
  3324.     psdrv.drawLine(stream, line_points, psdrv.StartX(), psdrv.row);
  3325.     psdrv.row -= LINE_WIDTH + psdrv.FontSize();
  3326.     lines++; // Increment the line count
  3327.  
  3328.     if(lines >= psdrv.LinesPerPage()) {
  3329.       psdrv.EndPage(stream);
  3330.       psdrv.StartPage(psdrv.page_count + 1, stream);
  3331.       if(orientation == 0)
  3332.     x_offset = int(HEADER_OFFSET * PIXELS_PER_INCH);
  3333.       else
  3334.     x_offset = PRINTABLE_OFFSET_X;
  3335.       psdrv.row = psdrv.StartY();
  3336.       lines = 4;
  3337.       psdrv.MoveTo(stream, psdrv.StartX(), psdrv.row);
  3338.       psdrv.ChangeFont(stream, item_font, font_size);
  3339.       x_offset = PrintPSItemBar(stream, psdrv, x_offset,
  3340.                 char_offset, cell_len);
  3341.       psdrv.ChangeFont(stream, cell_font, font_size);
  3342.       if(orientation == 0)
  3343.     line_points = int(x_offset - (HEADER_OFFSET * PIXELS_PER_INCH));
  3344.       else
  3345.     line_points = x_offset - PRINTABLE_OFFSET_X;
  3346.       psdrv.row -= (int)psdrv.FontSize();
  3347.       lines++;
  3348.       psdrv.drawThickLine(stream, line_points, psdrv.StartX(), psdrv.row);
  3349.       psdrv.row -= THICK_LINE_WIDTH + psdrv.FontSize();
  3350.       lines ++;
  3351.     }
  3352.     dllistptr = dllistptr->GetNext();
  3353.   }
  3354.   psdrv.EndPage(stream);
  3355.   PostScriptPrintTotals(textWin, stream, psdrv);
  3356.   stream.close();
  3357. }  
  3358.  
  3359. void PostScriptPrintTotals(MyTextWindow &textWin, ofstream &stream,
  3360.                PostScriptDrv &psdrv)
  3361. {
  3362.   psdrv.StartPage(psdrv.page_count + 1, stream);
  3363.   double tax_font_size = 15;
  3364.   psdrv.ChangeFont(stream, PostScriptDrv::COURIER_BOLD, tax_font_size);
  3365.   psdrv.row = psdrv.StartY();
  3366.  
  3367.   char sbuffer[sbuffer_len];
  3368.   psdrv.row -= tax_font_size * 2; // Offset the tax from the header
  3369.   sprintf(sbuffer, "TOTAL BEFORE TAX = $%.2f", grand_total);
  3370.   psdrv.MoveTo(stream, psdrv.StartX(), psdrv.row);
  3371.   psdrv.PrintLine(sbuffer, stream);
  3372.  
  3373.   if(sales_tax <= 0) {
  3374.     textWin << "Finished." << "\n";
  3375.     psdrv.EndPage(stream);
  3376.     psdrv.Epilogue(stream, psdrv.page_count);
  3377.     stream.close();
  3378.     return; 
  3379.   }
  3380.  
  3381.   double tax_percent = sales_tax / 100;
  3382.   double tax = tax_percent * grand_total;
  3383.   double tax_total = grand_total;
  3384.   
  3385.   int i;
  3386.   psdrv.row -= tax_font_size * 2;
  3387.   for(i = 0; i < sbuffer_len; i++) sbuffer[i] = '\0';
  3388.   sprintf(sbuffer, "SALES TAX = $%.2f", tax);
  3389.   psdrv.MoveTo(stream, psdrv.StartX(), psdrv.row);
  3390.   psdrv.PrintLine(sbuffer, stream);
  3391.   
  3392.   psdrv.row -= tax_font_size * 2;
  3393.   for(i = 0; i < sbuffer_len; i++) sbuffer[i] = '\0';
  3394.   tax_total += tax;
  3395.   sprintf(sbuffer, "GRAND TOTAL= $%.2f", tax_total);
  3396.   psdrv.MoveTo(stream, psdrv.StartX(), psdrv.row);
  3397.   psdrv.PrintLine(sbuffer, stream);
  3398.  
  3399.   psdrv.EndPage(stream);
  3400.   psdrv.Epilogue(stream, psdrv.page_count);
  3401.   textWin << "Finished." << "\n";
  3402.   stream.close();
  3403. }
  3404.  
  3405. #ifdef __USE_MSW_PRINTING__
  3406.  
  3407. void page_btn_proc(wxButton& but, wxCommandEvent& event)
  3408. // Button procedures for the MSW Page Setup Dialog box
  3409. {
  3410.   long tag = (long)but.GetClientData() ;
  3411.  
  3412.   if(tag == PAGE_DIALOG_BUTTON_CLOSE) {
  3413.     wxPageDialog->Show(FALSE);
  3414.     delete wxPageDialog;
  3415.   }
  3416.  
  3417.   if(tag == PAGE_DIALOG_BUTTON_ACCEPT) {
  3418.     MSWPrintSetup->lines_per_page = LppSlider->GetValue();
  3419.     MSWPrintSetup->cell_length = CellSlider->GetValue();
  3420.     MSWPrintSetup->font_size = FsSlider->GetValue();
  3421.     MSWPrintSetup->orientation = OrientationChoice->GetSelection();
  3422.     MSWPrintSetup->font = FontChoice->GetSelection();
  3423.     MSWPrintSetup->lr_margin = LRMSlider->GetValue();
  3424.     
  3425.     MSWPrintSetup->prev_lines_per_page = LppSlider->GetValue();
  3426.     MSWPrintSetup->prev_cell_length = CellSlider->GetValue();
  3427.     MSWPrintSetup->prev_font_size = FsSlider->GetValue();
  3428.     MSWPrintSetup->prev_orientation = OrientationChoice->GetSelection();
  3429.     MSWPrintSetup->prev_font = FontChoice->GetSelection();
  3430.     MSWPrintSetup->prev_lr_margin = LRMSlider->GetValue();
  3431.   }
  3432.  
  3433.   if(tag == PAGE_DIALOG_BUTTON_CANCEL) {
  3434.     LppSlider->SetValue(MSWPrintSetup->prev_lines_per_page);
  3435.     CellSlider->SetValue(MSWPrintSetup->prev_cell_length);
  3436.     FsSlider->SetValue(MSWPrintSetup->prev_font_size);
  3437.     OrientationChoice->SetSelection(MSWPrintSetup->prev_orientation);
  3438.     FontChoice->SetSelection(MSWPrintSetup->prev_font);
  3439.     LRMSlider->SetValue(MSWPrintSetup->prev_lr_margin);
  3440.   }
  3441.  
  3442.   if(tag == PAGE_DIALOG_BUTTON_DEFAULT) {
  3443.     LppSlider->SetValue(MSWPrintSetup->default_lines_per_page);
  3444.     CellSlider->SetValue(MSWPrintSetup->default_cell_length);
  3445.     FsSlider->SetValue(MSWPrintSetup->default_font_size);
  3446.     OrientationChoice->SetSelection(MSWPrintSetup->default_orientation);
  3447.     FontChoice->SetSelection(MSWPrintSetup->default_font);
  3448.     LRMSlider->SetValue(MSWPrintSetup->default_lr_margin);
  3449.   }
  3450. }
  3451.  
  3452. void wGrocPrint::SetFont(int style, int weight)
  3453. {
  3454.   switch(MSWPrintSetup->font) {
  3455.     case 0:
  3456.       printerFont = wxTheFontList->FindOrCreateFont(MSWPrintSetup->font_size,
  3457.                             wxSWISS, style, weight);
  3458.       char_width = .6 * MSWPrintSetup->font_size;
  3459.       break;
  3460.  
  3461.     case 1:
  3462.       printerFont = wxTheFontList->FindOrCreateFont(MSWPrintSetup->font_size,
  3463.                             wxROMAN, style, weight);
  3464.       char_width = .6 * MSWPrintSetup->font_size;
  3465.       break;
  3466.  
  3467.     case 2:
  3468.       printerFont = wxTheFontList->FindOrCreateFont(MSWPrintSetup->font_size,
  3469.                             wxDECORATIVE,
  3470.                             style, weight);
  3471.       char_width = .6 * MSWPrintSetup->font_size;
  3472.       break;
  3473.  
  3474.     case 3:
  3475.       printerFont = wxTheFontList->FindOrCreateFont(MSWPrintSetup->font_size,
  3476.                             wxMODERN, style, weight);
  3477.       char_width = .6 * MSWPrintSetup->font_size;
  3478.       break;
  3479.     
  3480.     case 4:
  3481.       printerFont = wxTheFontList->FindOrCreateFont(MSWPrintSetup->font_size,
  3482.                             wxSCRIPT, style, weight);
  3483.       char_width = .6 * MSWPrintSetup->font_size;
  3484.       break;
  3485.  
  3486.     case 5:
  3487.       printerFont = wxTheFontList->FindOrCreateFont(MSWPrintSetup->font_size,
  3488.                             wxDEFAULT, style, weight);
  3489.       char_width = .6 * MSWPrintSetup->font_size;
  3490.       break;
  3491.  
  3492.     default:
  3493.       printerFont = wxTheFontList->FindOrCreateFont(MSWPrintSetup->font_size,
  3494.                             wxSWISS, style, weight);
  3495.       char_width = .6 * MSWPrintSetup->font_size;
  3496.       break;
  3497.   };
  3498. }
  3499.  
  3500. void wGrocPrint::SetItemBarFont(int style, int weight)
  3501. {
  3502.   switch(MSWPrintSetup->font) {
  3503.     case 0:
  3504.       itembarFont = wxTheFontList->FindOrCreateFont(MSWPrintSetup->font_size,
  3505.                             wxSWISS, style, weight);
  3506.       break;
  3507.  
  3508.     case 1:
  3509.       itembarFont = wxTheFontList->FindOrCreateFont(MSWPrintSetup->font_size,
  3510.                             wxROMAN, style, weight);
  3511.       break;
  3512.  
  3513.     case 2:
  3514.       itembarFont = wxTheFontList->FindOrCreateFont(MSWPrintSetup->font_size,
  3515.                             wxDECORATIVE,
  3516.                             style, weight);
  3517.       break;
  3518.  
  3519.     case 3:
  3520.       itembarFont = wxTheFontList->FindOrCreateFont(MSWPrintSetup->font_size,
  3521.                             wxMODERN, style, weight);
  3522.       break;
  3523.     
  3524.     case 4:
  3525.       itembarFont = wxTheFontList->FindOrCreateFont(MSWPrintSetup->font_size,
  3526.                             wxSCRIPT, style, weight);
  3527.       break;
  3528.  
  3529.     case 5:
  3530.       itembarFont = wxTheFontList->FindOrCreateFont(MSWPrintSetup->font_size,
  3531.                             wxDEFAULT, style, weight);
  3532.       break;
  3533.  
  3534.     default:
  3535.       itembarFont = wxTheFontList->FindOrCreateFont(MSWPrintSetup->font_size,
  3536.                             wxSWISS, style, weight);
  3537.       break;
  3538.   };
  3539. }
  3540.  
  3541. void wGrocPrint::OnPreparePrinting()
  3542. // Called once by the framework before any other demands are made
  3543. // of the wxPrintout object. 
  3544. {
  3545.   SetFont();
  3546.   SetItemBarFont();
  3547.   SetHeaderFont(15, wxSWISS, wxNORMAL, wxBOLD);
  3548. }
  3549.  
  3550. Bool wGrocPrint::OnPrintPage(int page)
  3551. // Called by the framework when a page should be printed.
  3552. // Returning FALSE cancels the print job. The application
  3553. // can use wxPrintout::GetDC to obtain a device context to
  3554. // draw on.
  3555. {
  3556.   wxDC *dc = GetDC();
  3557.   if(dc) {
  3558.       DrawTextPage(dc, page);
  3559.     return TRUE;
  3560.   }
  3561.   else
  3562.     return FALSE;
  3563. }
  3564.  
  3565. Bool wGrocPrint::OnBeginDocument(int startPage, int endPage)
  3566. // Called by the framework at the start of document printing.
  3567. // OnBeginDocument is called once for every copy printed. 
  3568. // The base wxPrintout::OnBeginDocument must be called
  3569. // (and the return value checked) from within the overriden
  3570. // function, since it calls wxDC::StartDoc.
  3571. {
  3572.   if (!wxPrintout::OnBeginDocument(startPage, endPage))
  3573.     return FALSE; // Returns FALSE if the print job is canceled
  3574.  
  3575.   return TRUE;
  3576. }
  3577.  
  3578. Bool wGrocPrint::HasPage(int pageNum)
  3579. // Should be overriden to return TRUE if the document has this page,
  3580. // or FALSE if not. Returning FALSE signifies the end of the document.
  3581. // By default, HasPage behaves as if the document has only one page.
  3582. {
  3583.   // Calculate the number of pages in this document
  3584.   int minPage, maxPage, selPageFrom, selPageTo;
  3585.   GetPageInfo(&minPage, &maxPage, &selPageFrom, &selPageTo);
  3586.   return (pageNum == minPage) || (pageNum <= maxPage);
  3587. }
  3588.  
  3589. void wGrocPrint::GetPageInfo(int *minPage, int *maxPage, int *selPageFrom,
  3590.                   int *selPageTo)
  3591. // Called by the framework to obtain information from the application
  3592. // about minimum and maximum page values that the user can select, and
  3593. // the required page range to be printed.
  3594. {
  3595.   if(DB->RebuildIndex()) { // The index files needs to be rebuilt
  3596.     *minPage = 1;
  3597.     *selPageFrom = 1;
  3598.     *selPageTo = 1;
  3599.     *maxPage = 1;
  3600.     return;
  3601.   }  
  3602.  
  3603.   if(print_list == 0) num_objects = LoadIndexKeys(print_all);
  3604.   if(dllist->IsEmpty()) num_objects = LoadIndexKeys(print_all);
  3605.   if(displaying_list == 1) {
  3606.     if(print_all == 0) ReOrderDisplayList();
  3607.   }
  3608.   
  3609.   dllistptr = dllist->GetFront();
  3610.   int lines = num_objects;
  3611.   int first_page = 1; // Always starting on page one
  3612.   last_page = 1;      // Default is the first page
  3613.   
  3614.   *minPage = first_page;     // Always starting on page one
  3615.   *selPageFrom = first_page; // Always starting on page one
  3616.  
  3617.   for(;;) {
  3618.     if(lines <= MSWPrintSetup->lines_per_page) break;
  3619.     lines = lines - MSWPrintSetup->lines_per_page;
  3620.     last_page++; // Increment the page count
  3621.   }
  3622.  
  3623.   last_page++; // Reserve a page to print the grand total
  3624.   
  3625.   *selPageTo = last_page;
  3626.   *maxPage = last_page;
  3627. }
  3628.  
  3629. void wGrocPrint::ScaleDC(wxDC *dc)
  3630. // Scale the DC so that the printout roughly represents the
  3631. // the screen scaling.
  3632. {
  3633.   // Get the page size 
  3634.   GetPageSizeMM(&page_width, &page_height);
  3635.   
  3636.     // Get the logical pixels per inch of screen and printer
  3637.   GetPPIScreen(&ppiScreenX, &ppiScreenY);
  3638.   GetPPIPrinter(&ppiPrinterX, &ppiPrinterY);
  3639.  
  3640.   // Scale the DC so that the printout roughly represents the
  3641.   // the screen scaling.
  3642.   scale = (float)((float)ppiPrinterX/(float)ppiScreenX);
  3643.  
  3644.   // Calculate conversion factor for converting millimetres into
  3645.   // logical units. There are approx. 25.1 mm to the inch. There
  3646.   // are ppi device units to the inch. Therefore 1 mm corresponds
  3647.   // to ppi/25.1 device units.
  3648.   logUnitsFactor = (float)(ppiPrinterX / (scale * 25.1));
  3649.  
  3650.   // Check real page size in case it is reduced by print preview 
  3651.   int pageWidth, pageHeight;
  3652.   float w, h;
  3653.   dc->GetSize(&w, &h);
  3654.   GetPageSizePixels(&pageWidth, &pageHeight);
  3655.   
  3656.   // Do not change if printer pageWidth == current DC width
  3657.   float overallScale = scale * (float)(w/(float)pageWidth);
  3658.   dc->SetUserScale(overallScale, overallScale);
  3659. }
  3660.  
  3661. void wGrocPrint::DrawTextPage(wxDC *dc, int page)
  3662. // Write page by page with margins, header, and page numbers
  3663. {
  3664.   dc->SetFont(itembarFont); // Set the text font for the item bar
  3665.   ScaleDC(dc);
  3666.   
  3667.   start_x = (float)(logUnitsFactor * MSWPrintSetup->lr_margin);
  3668.   start_y = (float)(logUnitsFactor * MSWPrintSetup->tb_margin);
  3669.  
  3670.   int end = page * MSWPrintSetup->lines_per_page;  // Last line to write
  3671.   int start = end - MSWPrintSetup->lines_per_page; // First line to write
  3672.  
  3673.   float textW, textH; // Text width and height 
  3674.   float xpos = start_x; 
  3675.   float ypos = start_y;
  3676.  
  3677.   int char_offset = int((MSWPrintSetup->cell_length + 1) * char_width);
  3678.   float x_offset = xpos;
  3679.  
  3680.   if(page != last_page) { // Do not print item bar on last page
  3681.     PrintText(dc, (char *)KeyName, MSWPrintSetup->cell_length,
  3682.           x_offset, ypos); 
  3683.     x_offset += char_offset;
  3684.     dc->GetTextExtent((char *)KeyName, &textW, &textH);
  3685.  
  3686.     PrintText(dc, (char *)M2Name, MSWPrintSetup->cell_length,
  3687.           x_offset, ypos); 
  3688.     x_offset += char_offset;
  3689.  
  3690.     PrintText(dc, (char *)M3Name, MSWPrintSetup->cell_length,
  3691.           x_offset, ypos); 
  3692.     x_offset += char_offset;
  3693.     
  3694.     PrintText(dc, (char *)M4Name, MSWPrintSetup->cell_length,
  3695.           x_offset, ypos); 
  3696.     x_offset += char_offset;
  3697.     
  3698.     PrintText(dc, (char *)M5Name, MSWPrintSetup->cell_length,
  3699.           x_offset, ypos); 
  3700.     x_offset += char_offset;
  3701.  
  3702.     PrintText(dc, (char *)M7Name, MSWPrintSetup->cell_length,
  3703.           x_offset, ypos); 
  3704.  
  3705.     // Do not draw a line past the member
  3706.     x_offset += int((strlen(M7Name) + 1) * char_width);
  3707.   }
  3708.   
  3709.   ypos += textH;
  3710.   dc->DrawLine(xpos , ypos, x_offset, ypos);
  3711.   ypos += mswpLINE_WIDTH;
  3712.  
  3713.   int lines = 0;
  3714.   Grocery grocery(DB);
  3715.   dc->SetFont(printerFont); // Set the text font for the objects
  3716.   
  3717.   for(int i = 0; i < start; i++) {
  3718.     if(!dllist->IsHeader(dllistptr)) 
  3719.       dllistptr = dllistptr->GetNext();
  3720.   }
  3721.  
  3722.   while(!dllist->IsHeader(dllistptr)) {
  3723.     grocery.ReadObject(dllistptr->Data.object_address);
  3724.     x_offset = xpos;
  3725.     ypos += mswpLINE_WIDTH;
  3726.  
  3727.     PrintText(dc, grocery.GetName(), MSWPrintSetup->cell_length,
  3728.           x_offset, ypos); 
  3729.     x_offset += char_offset;
  3730.     dc->GetTextExtent(grocery.GetName(), &textW, &textH);
  3731.  
  3732.     PrintText(dc, grocery.GetBrand(), MSWPrintSetup->cell_length,
  3733.           x_offset, ypos); 
  3734.     x_offset += char_offset;
  3735.       
  3736.     PrintText(dc, grocery.GetStore(), MSWPrintSetup->cell_length,
  3737.           x_offset, ypos); 
  3738.     x_offset += char_offset;
  3739.     
  3740.     PrintText(dc, (double)grocery.GetPrice(), MSWPrintSetup->cell_length,
  3741.           x_offset, ypos); 
  3742.     x_offset += char_offset;
  3743.     
  3744.     PrintText(dc, (long)grocery.GetQuantity(), MSWPrintSetup->cell_length,
  3745.           x_offset, ypos); 
  3746.     x_offset += char_offset;
  3747.     
  3748.     PrintText(dc, (double)grocery.GetLineTotal(), MSWPrintSetup->cell_length,
  3749.           x_offset, ypos); 
  3750.  
  3751.     // Do not draw a line past the member
  3752.     x_offset += int((strlen(M7Name) + 1) * char_width);
  3753.     
  3754.     ypos += textH;
  3755.     ypos += mswpLINE_WIDTH;
  3756.     dc->DrawLine(xpos , ypos, x_offset, ypos);
  3757.     ypos += mswpLINE_WIDTH;
  3758.     lines++;
  3759.     if(lines >= MSWPrintSetup->lines_per_page) break;
  3760.     dllistptr = dllistptr->GetNext();
  3761.   }
  3762.   
  3763.   char time_buf[sbuffer_len]; // Buffer used to hold time/date string
  3764.   GetSystemTime(time_buf);    // Part of the PostScript Driver class
  3765.   WritePageHeader(dc, mswpDocumentName, time_buf);
  3766.   WritePageNumber(dc, page);
  3767.  
  3768.   // Print the grand total
  3769.   if(page == last_page) {
  3770.     dc->SetFont(headerFont);
  3771.     char sbuffer[sbuffer_len];
  3772.     xpos = start_x; ypos = start_y;
  3773.  
  3774.     sprintf(sbuffer, "TOTAL BEFORE TAX = $%.2f", grand_total);
  3775.     dc->GetTextExtent(sbuffer, &textW, &textH);
  3776.     ypos += textH * 2; // Offset text from the page header
  3777.     PrintText(dc, sbuffer, xpos, ypos);
  3778.  
  3779.     if(sales_tax <= 0) 
  3780.       return; // No sales tax info in the config file
  3781.  
  3782.     double tax_percent = sales_tax / 100;
  3783.     double tax = tax_percent * grand_total;
  3784.     double tax_total = grand_total;
  3785.     
  3786.     ypos += textH * 2;
  3787.     for(i = 0; i < sbuffer_len; i++) sbuffer[i] = '\0';
  3788.     sprintf(sbuffer, "SALES TAX = $%.2f", tax);
  3789.     dc->GetTextExtent(sbuffer, &textW, &textH);
  3790.     PrintText(dc, sbuffer, xpos, ypos);
  3791.  
  3792.     ypos += textH * 2; // Offest from header
  3793.     for(i = 0; i < sbuffer_len; i++) sbuffer[i] = '\0';
  3794.     tax_total += tax;
  3795.     sprintf(sbuffer, "GRAND TOTAL = $%.2f", tax_total);
  3796.     PrintText(dc, sbuffer, xpos, ypos);
  3797.   }
  3798. }
  3799.  
  3800. void wGrocPrint::SetHeaderFont(int size, int font, int style, int weight)
  3801. // Set the header and page number font type, size, and style
  3802. {
  3803.   headerFont = wxTheFontList->FindOrCreateFont(size, font, style, weight);
  3804. }
  3805.  
  3806. void wGrocPrint::WritePageHeader(wxDC *dc, char *doc_name, char *doc_date)
  3807. // Writes header on top of page. Margin units are in millimetres.
  3808. {
  3809.   dc->SetFont(headerFont);
  3810.  
  3811.   // Offset the margins to move text above the first line
  3812.   int leftMargin  = MSWPrintSetup->lr_margin / 2;
  3813.   int topMargin   = MSWPrintSetup->tb_margin / 2;
  3814.   int rightMargin = MSWPrintSetup->lr_margin / 2;
  3815.  
  3816.   float leftMarginLogical = (float)(logUnitsFactor * leftMargin);
  3817.   float topMarginLogical = (float)(logUnitsFactor * topMargin);
  3818.   float rightMarginLogical = (float)(logUnitsFactor* \
  3819.                      (page_width - rightMargin));
  3820.  
  3821.   float xExtentName, yExtentName, xExtentDate, yExtentDate, xPos, offset;
  3822.   dc->GetTextExtent(doc_name, &xExtentName, &yExtentName);
  3823.   if(doc_date != 0) { // Printing document name and date strings
  3824.     dc->GetTextExtent(doc_date, &xExtentDate, &yExtentDate);
  3825.  
  3826.     // Draw the document's name left justified
  3827.     PrintText(dc, doc_name, start_x, topMarginLogical);
  3828.  
  3829.     // Draw the document's date right justified
  3830.     if(MSWPrintSetup->orientation == 0) // Landscape printing
  3831.       offset = (logUnitsFactor * page_width) - \
  3832.        (logUnitsFactor * (MSWPrintSetup->lr_margin + mswpPRINTABLE_OFFSET_X));
  3833.     else
  3834.       offset = (logUnitsFactor * page_width) - \
  3835.     (logUnitsFactor * (MSWPrintSetup->lr_margin + mswpPRINTABLE_OFFSET_X));
  3836.       
  3837.     xPos = (float)(offset - xExtentDate);
  3838.     PrintText(dc, doc_date, xPos, topMarginLogical);
  3839.   }
  3840.   else { // Center the document's name
  3841.     xPos = (float)(((((page_width - leftMargin - rightMargin)/2.0)
  3842.              +leftMargin)*logUnitsFactor) - (xExtentName/2.0));
  3843.     PrintText(dc, doc_name, xPos, topMarginLogical);
  3844.   }
  3845. }
  3846.  
  3847. void wGrocPrint::WritePageNumber(wxDC *dc, int pagenum)
  3848. // Writes page number on bottom of page. Margin units are in millimetres.
  3849. {
  3850.   dc->SetFont(headerFont);
  3851.  
  3852.   // Offset the margins to move text below the last line
  3853.   int leftMargin = MSWPrintSetup->lr_margin;
  3854.   int bottomMargin = MSWPrintSetup->tb_margin;
  3855.   int rightMargin = MSWPrintSetup->lr_margin;
  3856.  
  3857.   float leftMarginLogical = (float)(logUnitsFactor * leftMargin);
  3858.  
  3859.   float bottomMarginLogical = (float)(logUnitsFactor * (page_height - \
  3860.                             bottomMargin));
  3861.  
  3862.   float rightMarginLogical = (float)(logUnitsFactor*(page_width - \
  3863.                              rightMargin));
  3864.   float xExtent, yExtent;
  3865.   char sbuffer[sbuffer_len];
  3866.   sprintf(sbuffer, "PAGE %d", pagenum);
  3867.   dc->GetTextExtent(sbuffer, &xExtent, &yExtent);
  3868.   float xPos = (float)(((((page_width - leftMargin - rightMargin)/2.0)
  3869.              +leftMargin)*logUnitsFactor) - (xExtent/2.0));
  3870.   PrintText(dc, sbuffer, xPos, bottomMarginLogical);
  3871. }
  3872.  
  3873. void wGrocPrint::PrintText(wxDC *dc, char *s, int max_len,
  3874.                float xpos, float ypos)
  3875. // Draw text in the device context.
  3876. {
  3877.   if(s == 0 || max_len <= 0) return;
  3878.   int slen = strlen(s);
  3879.   if(slen > max_len) {
  3880.     char *buf = new char[max_len];
  3881.     buf[max_len] = '\0';
  3882.     memmove(buf, s, max_len);
  3883.     dc->DrawText(buf, xpos, ypos);
  3884.     delete [] buf;
  3885.   }
  3886.   else
  3887.     dc->DrawText(s, xpos, ypos);
  3888. }
  3889.  
  3890. void wGrocPrint::PrintText(wxDC *dc, char *s, float xpos, float ypos)
  3891. // Draw text in the device context.
  3892. {
  3893.   if(s == 0) return;
  3894.   dc->DrawText(s, xpos, ypos);
  3895. }
  3896.  
  3897. void wGrocPrint::PrintText(wxDC *dc, char c, float xpos, float ypos)
  3898. {
  3899.   char s[1];
  3900.   s[0] = c;    // Copy char into a string buffer
  3901.   s[1] = '\0'; // Null terminate the string
  3902.   PrintText(dc, s, xpos, ypos);
  3903. }
  3904.  
  3905. void wGrocPrint::PrintText(wxDC *dc, int i, int max_len,
  3906.                float xpos, float ypos)
  3907. {
  3908.   char sbuffer[sbuffer_len];
  3909.   sprintf(sbuffer, "%d", i);
  3910.   PrintText(dc, sbuffer, max_len, xpos, ypos);
  3911. }
  3912.  
  3913. void wGrocPrint::PrintText(wxDC *dc, long i, int max_len,
  3914.                float xpos, float ypos)
  3915. {
  3916.   char sbuffer[sbuffer_len];
  3917.   sprintf(sbuffer, "%d", i);
  3918.   PrintText(dc, sbuffer, max_len, xpos, ypos);
  3919. }
  3920.  
  3921. void wGrocPrint::PrintText(wxDC *dc, double i, int max_len,
  3922.                float xpos, float ypos)
  3923. {
  3924.   char sbuffer[sbuffer_len];
  3925.   sprintf(sbuffer, "%.2f", i);
  3926.   PrintText(dc, sbuffer, max_len, xpos, ypos);
  3927. }
  3928.  
  3929. void wGrocPrint::PrintText(wxDC *dc, float i, int max_len,
  3930.                float xpos, float ypos)
  3931. {
  3932.   char sbuffer[sbuffer_len];
  3933.   sprintf(sbuffer, "%.2f", i);
  3934.   PrintText(dc, sbuffer, max_len, xpos, ypos);
  3935. }
  3936.  
  3937. void wGrocPrint::PrintText(wxDC *dc, int i, float xpos, float ypos)
  3938. {
  3939.   char sbuffer[sbuffer_len];
  3940.   sprintf(sbuffer, "%d", i);
  3941.   PrintText(dc, sbuffer, xpos, ypos);
  3942. }
  3943.  
  3944. void wGrocPrint::PrintText(wxDC *dc, long i, float xpos, float ypos)
  3945. {
  3946.   char sbuffer[sbuffer_len];
  3947.   sprintf(sbuffer, "%d", i);
  3948.   PrintText(dc, sbuffer, xpos, ypos);
  3949. }
  3950.  
  3951. void wGrocPrint::PrintText(wxDC *dc, double i, float xpos, float ypos)
  3952. {
  3953.   char sbuffer[sbuffer_len];
  3954.   sprintf(sbuffer, "%.2f", i);
  3955.   PrintText(dc, sbuffer, xpos, ypos);
  3956. }
  3957.  
  3958. void wGrocPrint::PrintText(wxDC *dc, float i, float xpos, float ypos)
  3959. {
  3960.   char sbuffer[sbuffer_len];
  3961.   sprintf(sbuffer, "%.2f", i);
  3962.   PrintText(dc, sbuffer, xpos, ypos);
  3963. }
  3964.  
  3965. #endif // __USE_MSW_PRINTING__
  3966.  
  3967. // ----------------------------------------------------------- //
  3968. // ------------------------------- //
  3969. // --------- End of File --------- //
  3970. // ------------------------------- //
  3971.  
  3972.